patronum icon indicating copy to clipboard operation
patronum copied to clipboard

`@@debug` protocol + integration for `debug` operator

Open NazariiShvets opened this issue 1 year ago • 3 comments

Proposal

Create protocol for debug operator, so it would be easy to debug factory instances

Problem

Current state of debug allows passing flat objects with units to debug operator But it integrates poorly with libraries like farfetched or atomic-router or any other library which, as result of factory call, returns nested objects (like forms which has form-level units and field-level units) or extra non-unit fields (like meta information or __ namespace for mocking in tests)

##Solution Allow libraries to expose units specificly for debuging via this protocol so users can just pass it into debug

API

It should return object so it could be easy to add meta info for debuging It should be possible to add grouping or prefix for logs, to allow so users could differenciate logs It should be flat object with units for easy integration with debug

So, something like that

@@debug: () => { name?: string; units: Record<string, Unit<any>> }

Examples

Atomic-router

function createRoute() {
 // implementation ...
 
  const instance = {
    $isOpened,
    $params,
    $query,
    opened,
    updated,
    closed,
    navigate: navigateFx,
    open: openFx,
    kind: Kind.ROUTE,
    // @ts-expect-error Internal stuff
    settings: {
      derived: Boolean(params.filter),
    },
    
    '@@debug': () => ({
       units: {
         $isOpened,
         $params,
         $query,
         opened,
         updated,
         closed,
         navigate: navigateFx,
         open: openFx,
       }
    })
  };
   
 return instance
}

debug(homePageRoute)

Farfetched

function createHeadlessQuery(config) {
  // Implementation ...
  
 return {
    // ....
    '@@unitShape': unitShapeProtocol,
    
    '@@debug': () => ({
       name: config.name,
       units: {
          reset: readonly(reset),
          refresh: readonly(refresh),
          start: readonly(operation.start),
          started: readonly(operation.started),
          $data: readonly($data),
          $error: readonly($error),
          $status: readonly(operation.$status),
          $idle: readonly(operation.$idle),
          $pending: readonly(operation.$pending),
          // ...
         $stale: readonly($stale),
         aborted: readonly(operation.aborted),
         "finished.success": readonly(operation.finished.success),
         "finished.failure": readonly(operation.finished.failure),
         "finished.finally": readonly(operation.finished.finally),
         "finished.skip": readonly(operation.finished.skip),
       }
    })
 }
}

debug(getDataQuery)

Filledout

function createForm(config) {
  // Implementation ...
  
  return {
    fields: createFields(config),
    
    '@@debug': () => ({
       units: {
          $values,
          $errors,
          $dirty,
          submit,
          reset,
          $valid,
          validateFx
       }
    })
  }
}

function createField(config) {
  // ...
  return {
     // ...
     '@@debug': () => ({
        units: {
          $value,
          $dirty,
          $valid,
          $errors,
          changed
        }
     })
  }
}

debug($$form, $$form.fields.email)

NazariiShvets avatar Sep 23 '23 01:09 NazariiShvets

I see a downside of such a protocol. It would increase bundle size even if you do not use debug operator.

igorkamyshev avatar Sep 23 '23 02:09 igorkamyshev

Well, if library really cares about bytes of bundle size, it can extract maping logic into separate utility, so it can be tree-shaked

debug(toDebug(query))

NazariiShvets avatar Sep 23 '23 13:09 NazariiShvets

Well, this could be done by separate lib like "my-debuger" 😇 maybe it's excessive to introduce protocol for something that anyway have to be done by a separate lib (because of bundle size)?

igorkamyshev avatar Sep 23 '23 13:09 igorkamyshev