PublicAPI.jl

PublicAPIModule

PublicAPI

Dev

NOTE: This is a proof-of-concept implementation of Feature request: Base.@public macro for declaring a public name without needing to export it · Issue #42117 · JuliaLang/julia.

PublicAPI.jl provides a simple API for declaring API without exporting the names:

using PublicAPI: @public
@public public_api_name
public_api_name() = 1

export exported_and_public_api_name
exported_and_public_api_name() = 2

The public API can be queried using PublicAPI.of(module). For example, the public API for PublicAPI.jl can be listed as:

julia> using PublicAPI

julia> apis = PublicAPI.of(PublicAPI);

julia> sort!(fullname.(apis))
3-element Vector{Tuple{Symbol, Symbol}}:
 (:PublicAPI, Symbol("@public"))
 (:PublicAPI, Symbol("@strict"))
 (:PublicAPI, :of)

Consumers of the public API can opt-in a stricter semantics of using via PublicAPI.@strict

import PublicAPI
PublicAPI.@strict using Upstream: api

which ensures that Upstream.api is either exported or marked as @public.

PublicAPI.@publicMacro
@public name₁ name₂ … nameₙ
@public @macroname

Declare public API names for the current module.

The second form @public @macroname is equivalent to @public var"@macroname".

Extended help

Note that where this macro is invoked is important. Consider:

module A1
    using PublicAPI: @public
    @public B, C
    module B
        f() = nothing
    end
    module C
        using PublicAPI: @public
        using ..B: f
        @public f
    end
end

and

module A2
    using PublicAPI: @public
    @public B, C
    module B
        using PublicAPI: @public
        f() = nothing
        @public f
    end
    module C
        using ..B: f
    end
end

The fully-qualified names A1.C.f and A2.B.f are public but A1.B.f and A2.C.f are private.

PublicAPI.@strictMacro
PublicAPI.@strict using Module: name₁, name₂, …, nameₙ
PublicAPI.@strict import Module

Enable strict import; i.e., fail on using non-public API.

The simple form import Module create a dummy object named Module that acts like the original Module but forbids access to the internal names.

Extended help

Limitation: Currently, PublicAPI.@strict with the simple form import Module creates a dummy local module and a global constant named Module is bind to it. Thus, unlike import Module, the expression PublicAPI.@strict import Module cannot be evaluated more than once inside a module. This is an implementation detail that may be fixed in the future if we find a better implementation.

PublicAPI.ofFunction
PublicAPI.of(provider::Module; [recursive = true]) -> apis::Vector

List public API from the provider module.

Each element api of apis supports the following accessor functions:

  • Module(api) :: Module: module in which the API is defined
  • nameof(api) :: Symbol: the name of the API in the module
  • fullname(api) :: Tuple{Vararg{Symbol}}: the components of the fully-qualified name; i.e., (:Package, :SubModule, :function) for Package.SubModule.function.

The provider module itself is not included in the apis.

Keyword Arguments

  • recursive::Bool = true: Include public APIs from public sub-modules.