Repository: swagger-api/swagger-ui (js)

Issue:
Path in $ref is partually percent-encoded
### Q&A
 - OS: windows
 - Browser: chrome
 - Version: 76.0.3809.132
 - Method of installation: no installation, issue is presented at editor.swagger.io
 - Swagger-Editor version: current editor.swagger.io
 - Swagger/OpenAPI version: Swagger 2.0

### Content & configuration
<!-- Provide us with a way to see what you're seeing, so that we can help. -->

Swagger/OpenAPI definition:
```
swagger:` '2.0'
info:
  description: 'Swagger docs'
  title: API example
  version: '1.0'
host: server
basePath: /docs
paths:
  '/ws/person':
    get:
      parameters:
        - name: id
          type: number
          in: path
          description: 'person id'
          required: true
      description: Get person
      operationId: 'get_person'
      tags:
        - Person
      responses:
        '200':
          description: Ok
          schema:
            type: object
            properties:
              result:
                $ref: '#/definitions/custom%3A%3Anamespace%3A%3APerson'
definitions:
  'custom::namespace::Person':
    properties:
      id:
        type: number
      FirstName:
        type: string
      LastName:
        type: string
      Address:
        type: array
        items:
          $ref: '#/definitions/custom%3A%3Anamespace%3A%3AAddress'
  'custom::namespace::Address':
    properties:
      id:
        type: number
      street:
        type: string
      city:
        type: string
```

### How can we help?
<!-- Your question or problem goes here! -->
In order to generate JSON without warnings some part $ref needs to be percent encoded, and not. Is this correct behavior, or maybe bug.

Way to reproduce this issue:
* Current JSON that contains part without and part with percent encoding will not have warnings.
* If we convert $ref without percent encoding warning will popup `$ref: '#/definitions/custom::namespace::Person'`
* If we convert $ref with all characters percent encoding warning will popup `$ref: '%23%2Fdefinitions%2Fcustom%3A%3Anamespace%3A%3APerson'`

Pull request description:
Decode model schema name on model component
### Description
Decodes the schema name on model 


### Motivation and Context
Fixes #5626 (for both OpenAPI v3 and Swagger V2)

### How Has This Been Tested?
- Go to `localhost:3200`
- Paste this data-url in  the url field

```
data:application/json;base64,eyJjb21wb25lbnRzIjp7InNjaGVtYXMiOnsiYVwvYitjIjp7InR5cGUiOiJudW1iZXIifX19LCJvcGVuYXBpIjoiMy4wLjMiLCJwYXRocyI6eyJcLyI6eyJnZXQiOnsicmVzcG9uc2VzIjp7ImRlZmF1bHQiOnsiY29udGVudCI6eyJhcHBsaWNhdGlvblwvanNvbiI6eyJzY2hlbWEiOnsiJHJlZiI6IiNcL2NvbXBvbmVudHNcL3NjaGVtYXNcL2F+MWIlMkJjIn19fX19fX19fQ==
```

- Expand `/` route
- Switch the default response from `example value` to `model`
- You should see `a/b+c`, without any `~1` or `%B2`

An data-uri to test Swagger v2 spec

```
data:application/yaml;base64,c3dhZ2dlcjogJzIuMCcKaW5mbzoKICBkZXNjcmlwdGlvbjogJ1N3YWdnZXIgZG9jcycKICB0aXRsZTogQVBJIGV4YW1wbGUKICB2ZXJzaW9uOiAnMS4wJwpob3N0OiBzZXJ2ZXIKYmFzZVBhdGg6IC9kb2NzCnBhdGhzOgogICcvd3MvcGVyc29uJzoKICAgIGdldDoKICAgICAgZGVzY3JpcHRpb246IEdldCBwZXJzb24KICAgICAgb3BlcmF0aW9uSWQ6ICdnZXRfcGVyc29uJwogICAgICB0YWdzOgogICAgICAgIC0gUGVyc29uCiAgICAgIHJlc3BvbnNlczoKICAgICAgICAnMjAwJzoKICAgICAgICAgIGRlc2NyaXB0aW9uOiBPawogICAgICAgICAgc2NoZW1hOgogICAgICAgICAgICB0eXBlOiBvYmplY3QKICAgICAgICAgICAgcHJvcGVydGllczoKICAgICAgICAgICAgICByZXN1bHQ6CiAgICAgICAgICAgICAgICAkcmVmOiAnIy9kZWZpbml0aW9ucy9jdXN0b20lM0ElM0FuYW1lc3BhY2UlM0ElM0FQZXJzb24nCmRlZmluaXRpb25zOgogICdjdXN0b206Om5hbWVzcGFjZTo6UGVyc29uJzoKICAgIHByb3BlcnRpZXM6CiAgICAgIGlkOgogICAgICAgIHR5cGU6IG51bWJlcgogICAgICBGaXJzdE5hbWU6CiAgICAgICAgdHlwZTogc3RyaW5nCiAgICAgIExhc3ROYW1lOgogICAgICAgIHR5cGU6IHN0cmluZwogICAgICBBZGRyZXNzOgogICAgICAgIHR5cGU6IGFycmF5CiAgICAgICAgaXRlbXM6CiAgICAgICAgICAkcmVmOiAnIy9kZWZpbml0aW9ucy9jdXN0b20lM0ElM0FuYW1lc3BhY2UlM0ElM0FBZGRyZXNzJwogICdjdXN0b206Om5hbWVzcGFjZTo6QWRkcmVzcyc6CiAgICBwcm9wZXJ0aWVzOgogICAgICBpZDoKICAgICAgICB0eXBlOiBudW1iZXIKICAgICAgc3RyZWV0OgogICAgICAgIHR5cGU6IHN0cmluZwogICAgICBjaXR5OgogICAgICAgIHR5cGU6IHN0cmluZwogICAgICAgIA==
```


### Screenshots (if appropriate):
<img width="338" alt="Screenshot 2023-02-21 at 10 15 54" src="https://user-images.githubusercontent.com/3241703/220354904-80c2be39-6436-41ac-b77d-bf10c24e9a1c.png">
Before screenshot in  #5626

### My PR contains... 
- [ ] No code changes (`src/` is unmodified: changes to documentation, CI, metadata, etc.)
- [ ] Dependency changes (any modification to dependencies in `package.json`)
- [x] Bug fixes (non-breaking change which fixes an issue)
- [ ] Improvements (misc. changes to existing features)
- [ ] Features (non-breaking change which adds functionality)

### My changes...
- [ ] are breaking changes to a public API (config options, System API, major UI change, etc).
- [ ] are breaking changes to a private API (Redux, component props, utility functions, etc.).
- [ ] are breaking changes to a developer API (npm script behavior changes, new dev system dependencies, etc).
- [x] are not breaking changes.

### Documentation
- [x] My changes do not require a change to the project documentation.
- [ ] My changes require a change to the project documentation.
- [ ] If yes to above: I have updated the documentation accordingly.

### Automated tests
- [ ] My changes can not or do not need to be tested.
- [x] My changes can and should be tested by unit and/or integration tests.
- [x] If yes to above: I have added tests to cover my changes.
- [ ] If yes to above: I have taken care to cover edge cases in my tests.
- [ ] All new and existing tests passed.


Patch:
diff --git a/src/core/components/model.jsx b/src/core/components/model.jsx
index e72edbd6..4b420f36 100644
--- a/src/core/components/model.jsx
+++ b/src/core/components/model.jsx
@@ -3,6 +3,16 @@ import ImmutablePureComponent from "react-immutable-pure-component"
 import ImPropTypes from "react-immutable-proptypes"
 import PropTypes from "prop-types"
 
+const decodeRefName = uri => {
+  const unescaped = uri.replace(/~1/g, "/").replace(/~0/g, "~")
+
+  try {
+    return decodeURIComponent(unescaped)
+  } catch {
+    return unescaped
+  }
+}
+
 export default class Model extends ImmutablePureComponent {
   static propTypes = {
     schema: ImPropTypes.map.isRequired,
@@ -22,10 +32,10 @@ export default class Model extends ImmutablePureComponent {
 
   getModelName =( ref )=> {
     if ( ref.indexOf("#/definitions/") !== -1 ) {
-      return ref.replace(/^.*#\/definitions\//, "")
+      return decodeRefName(ref.replace(/^.*#\/definitions\//, ""))
     }
     if ( ref.indexOf("#/components/schemas/") !== -1 ) {
-      return ref.replace(/^.*#\/components\/schemas\//, "")
+      return decodeRefName(ref.replace(/^.*#\/components\/schemas\//, ""))
     }
   }
 


Test patch:
diff --git a/test/unit/core/helpers/get-model-name.js b/test/unit/core/helpers/get-model-name.js
new file mode 100644
index 00000000..2dbdd99c
--- /dev/null
+++ b/test/unit/core/helpers/get-model-name.js
@@ -0,0 +1,39 @@
+/**
+ * @prettier
+ */
+
+import Model from "../../../../src/core/components/model"
+
+describe("getModelName", () => {
+  const model = new Model()
+
+  it("should decode JSON Pointer and URI encoding for OpenAPI v3 refs", () => {
+    const actual = model.getModelName("#/components/schemas/a~1b%2Bc")
+    const expected = "a/b+c"
+
+    expect(actual).toStrictEqual(expected)
+  })
+
+  it("should decode JSON Pointer and URI encoding for Swagger v2 refs", () => {
+    const actual = model.getModelName(
+      "#/definitions/custom%3A%3Anamespace%3A%3APerson"
+    )
+    const expected = "custom::namespace::Person"
+
+    expect(actual).toStrictEqual(expected)
+  })
+
+  it("should decode multiple json-pointer values", () => {
+    const actual = model.getModelName("#/components/schemas/~1~1~0~0")
+    const expected = "//~~"
+
+    expect(actual).toStrictEqual(expected)
+  })
+
+  it("should support invalid URI encoding", () => {
+    const actual = model.getModelName("#/components/schemas/%25%d")
+    const expected = "%25%d"
+
+    expect(actual).toStrictEqual(expected)
+  })
+})