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

Replacement-value is presumably passed by reference instead of being passed by value #349

Open
aeworxet opened this issue May 13, 2024 · 1 comment

Comments

@aeworxet
Copy link

aeworxet commented May 13, 2024

I am observing weird behavior during dereference, which I am wary to call a 'bug', because most probably it's a result of JS limitations and not an algorithmic flaw.

In a

YAML
asyncapi: 3.0.0
info:
  title: Example Service
  version: 1.0.0
  description: Example Service.
channels:
  commentLikedChannel:
    $ref: './test/integration/bundle/channels.yaml#/channels/commentLikedChannel'
  userSignedup:
    address: 'user/signedup'
    messages:
      userSignedUpMessage:
        $ref: './test/integration/bundle/messages.yaml#/messages/UserSignedUp'
  test:
    address: '/test'
    messages:
      testMessage:
        $ref: '#/components/messages/TestMessage'
operations:
  UserSignedUp:
    action: send
    channel:
      $ref: '#/channels/userSignedup'
    messages:
      - $ref: '#/channels/userSignedup/messages/userSignedUpMessage'
  TestOpp:
    action: send
    channel:
      $ref: '#/channels/test'
    messages:
      - $ref: '#/channels/test/messages/testMessage'
components:
  messages:
    TestMessage:
      payload:
        type: string

an additional property is saved both to objects BEING dereferenced and THAT CONTAINS information attached in place of a $ref.

dereferenced YAML
asyncapi: 3.0.0
info:
  title: Example Service
  version: 1.0.0
  description: Example Service.
channels:
  commentLikedChannel:
    address: comment/liked
    x-origin: ./channels.yaml#/channels/commentLikedChannel
  userSignedup:
    address: user/signedup
    messages:
      userSignedUpMessage:
        payload:
          type: object
          properties:
            displayName:
              type: string
              description: Name of the user
            email:
              type: string
              format: email
              description: Email of the user
        x-origin: ./messages.yaml#/messages/UserSignedUp
  test:
    address: /test
    messages:
      testMessage:
        payload:                                        # | <-- object from below,
          type: string                                  # | <-- dereferencing is done correctly
        x-origin: '#/components/messages/TestMessage'   # | this property is expected to be added
operations:
  UserSignedUp:
    action: send
    channel:
      $ref: '#/channels/userSignedup'
    messages:
      - $ref: '#/channels/userSignedup/messages/userSignedUpMessage'
  TestOpp:
    action: send
    channel:
      $ref: '#/channels/test'
    messages:
      - $ref: '#/channels/test/messages/testMessage'
components:
  messages:
    TestMessage:
      payload:
        type: string
      x-origin: '#/components/messages/TestMessage'     # <-- but this property shouldn't be here after dereference of the above object

I suspect the reason for such behavior is that the replacement-value is passed to the object being dereferenced by reference and not by value. I think so, because I tried changing the names of both objects so they are not the same (to exclude the possibility that the second object is hitting a cache entry in a Set() and thus is being served back the same value) and changes to one object are still mirrored to the other one.

I have traced this behavior up to the crawl() function. Before it, the YAML was still intact, and after it, it already contained this unexpected change.

If my guess of passing an object by reference gets confirmed, I would suggest replacing objects' assignments with cloning using the ECMAScript 2022's structuredClone() method that creates a deep clone of a given value using the structured clone algorithm.

The code used for dereferencing: https://github.com/asyncapi/bundler/blob/master/src/parser.ts#L45

I have to differentiate internal JSON Pointers into those that SHOULD be dereferenced and those that SHOULD NOT, so I use dereference with conditions instead of unconditional bundle.

(x-origin is a property containing the historical value of a dereferenced $ref, meant mainly for humans' reference where the $ref came from, thus it's not important for the story)

francocm added a commit to francocm/asyncapi-cli that referenced this issue May 13, 2024
…ope of this PR will ignore the extra component block
@aeworxet aeworxet changed the title Dereferencing object is presumably passed by reference instead of being passed by value Replacement-value is presumably passed by reference instead of being passed by value May 29, 2024
@aeworxet
Copy link
Author

Is there an update on this issue?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant