Skip to content

Supporting generated nested namespaces #2582

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

Closed
greggman opened this issue Jun 1, 2024 · 2 comments
Closed

Supporting generated nested namespaces #2582

greggman opened this issue Jun 1, 2024 · 2 comments
Milestone

Comments

@greggman
Copy link

greggman commented Jun 1, 2024

Search terms

"namespace" finds #2055

Question

I have a generic function that generates a set of typed functions. You can think if it as it generates an API for the type. Then I have a function that generates a collection of APIs for some types.

I'd like to mark these as namespaces but I'm not having any luck.

Here's some sample code

export type BaseArgType = Float32Array | Float64Array | number[];

export type VecArg = BaseArgType;

/**
 * A specific concrete Vector Type
 */
export type VecType<T extends VecArg> = T;

type VecCtor<T extends VecArg>  = new (n: number) => T;

/**
 * Generates a typed API
 */
export function getFooAPIImpl<VecType extends VecArg>(Ctor: VecCtor<VecType>) {

  /**
   * Adds two vectors; assumes a and b have the same dimension.
   * @param a - Operand vector.
   * @param b - Operand vector.
   * @param dst - vector to hold result. If not passed in a new one is created.
   * @returns A vector that is the sum of a and b.
   */
  function add<T extends VecArg = VecType>(a: VecArg, b: VecArg, dst?: T) {
    const newDst = (dst ?? new Ctor(3)) as T;

    newDst[0] = a[0] + b[0];
    newDst[1] = a[1] + b[1];
    newDst[2] = a[2] + b[2];

    return newDst;
  }

  /**
   * Subtracts two vectors.
   * @param a - Operand vector.
   * @param b - Operand vector.
   * @param dst - vector to hold result. If not passed in a new one is created.
   * @returns A vector that is the difference of a and b.
   */
  function subtract<T extends VecArg = VecType>(a: VecArg, b: VecArg, dst?: T) {
    const newDst = (dst ?? new Ctor(3)) as T;

    newDst[0] = a[0] - b[0];
    newDst[1] = a[1] - b[1];
    newDst[2] = a[2] - b[2];

    return newDst;
  }

  return {
    add,
    subtract,
  };
}

export function getBarAPIImpl<VecType extends VecArg = Float32Array>(Ctor: VecCtor<VecType>) {

  /**
   * Multiplies a vector by another vector (component-wise); assumes a and
   * b have the same length.
   * @param a - Operand vector.
   * @param b - Operand vector.
   * @param dst - vector to hold result. If not passed in a new one is created.
   * @returns The vector of products of entries of a and b.
   */
   function multiply<T extends VecArg = VecType>(a: VecArg, b: VecArg, dst?: T) {
    const newDst = (dst ?? new Ctor(3)) as T;

    newDst[0] = a[0] * b[0];
    newDst[1] = a[1] * b[1];
    newDst[2] = a[2] * b[2];

    return newDst;
  }

  /**
   * Divides a vector by another vector (component-wise); assumes a and
   * b have the same length.
   * @param a - Operand vector.
   * @param b - Operand vector.
   * @param dst - vector to hold result. If not passed in a new one is created.
   * @returns The vector of quotients of entries of a and b.
   */
  function divide<T extends VecArg = VecType>(a: VecArg, b: VecArg, dst?: T) {
    const newDst = (dst ?? new Ctor(3)) as T;

    newDst[0] = a[0] / b[0];
    newDst[1] = a[1] / b[1];
    newDst[2] = a[2] / b[2];

    return newDst;
  }

  return {
    multiply,
    divide,
  };
}

/**
 * Don't need docs for this
 * @param Ctor1 - Constructor for FooAPI vectors
 * @param Ctor2 - Constructor for BarAPI vectors
 * @returns An object containing both Foo and Bar APIs
 */
function getAPIs<
  T1 extends VecArg,
  T2 extends VecArg,
>(
  Ctor1: VecCtor<T1>,
  Ctor2: VecCtor<T2>,
) {
  /** @namespace */
  const foo = getFooAPIImpl<T1>(Ctor1);
  /** @namespace */
  const bar = getBarAPIImpl<T2>(Ctor2);

  return { foo, bar };
}

/** @namespace */
export const f32API = getAPIs(Float32Array, Float32Array);
/** @namespace */
export const f64API = getAPIs(Float64Array, Float64Array);

What I'm hoping to get is

[N] f32API
  [N] foo
    [F] add
    [F] subtract
  [N] bar
    [F] multiply
    [F] divide
[N] f64API
  [N] foo
    [F] add
    [F] subtract
  [N] bar
    [F] multiply
    [F] divide

Where [N] = namespace and [F] = function

What I get instead is

[N] f32API
  [V] foo
  [V] bar
[N] f64API
  [V] foo
  [V] bar

Where [N] namespace and [V] = variable

And then, clicking foo or bar brings up a single page for that branch with all the functions on it

Is there a tag I can add that would do this or a way to restructure my code that would do this or is maybe typedoc not able to do this at the moment?

@greggman greggman added the question Question about functionality label Jun 1, 2024
Gerrit0 added a commit that referenced this issue Jun 1, 2024
@Gerrit0
Copy link
Collaborator

Gerrit0 commented Jun 1, 2024

With 0.25 this isn't supported - @namespace is only permitted on variable declarations, and TypeDoc will actually crash if you put it somewhere else.

With 0.26, I just made it so that the following will work:

    return {
        /** A comment @namespace*/
        a,
        /** B comment @namespace */
        b: getApi(Ctor2),
    };

Note that the comment is within the return object not on the variable declaration. While comments on the declaration work for functions (due to being attached to the signature, not the symbol) TS considers the appearance in the return object to be the source declaration.

@Gerrit0 Gerrit0 added this to the v0.26.0 milestone Jun 1, 2024
@greggman
Copy link
Author

greggman commented Jun 1, 2024

wow! Thank you. Verified it works.

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

2 participants