{"id":16024279,"url":"https://github.com/axelson/priv_check","last_synced_at":"2025-06-29T18:03:10.009Z","repository":{"id":57536554,"uuid":"237685669","full_name":"axelson/priv_check","owner":"axelson","description":"Library to check for private api usage in Elixir","archived":false,"fork":false,"pushed_at":"2020-11-11T17:29:37.000Z","size":155,"stargazers_count":9,"open_issues_count":6,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-06-10T14:59:44.547Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/axelson.png","metadata":{"files":{"readme":"README.md","changelog":"Changelog.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-02-01T22:17:34.000Z","updated_at":"2022-07-29T18:18:39.000Z","dependencies_parsed_at":"2022-08-29T00:50:27.084Z","dependency_job_id":null,"html_url":"https://github.com/axelson/priv_check","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/axelson/priv_check","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/axelson%2Fpriv_check","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/axelson%2Fpriv_check/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/axelson%2Fpriv_check/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/axelson%2Fpriv_check/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/axelson","download_url":"https://codeload.github.com/axelson/priv_check/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/axelson%2Fpriv_check/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":260739732,"owners_count":23055201,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-08T19:06:24.441Z","updated_at":"2025-06-29T18:03:09.978Z","avatar_url":"https://github.com/axelson.png","language":"Elixir","funding_links":[],"categories":[],"sub_categories":[],"readme":"# PrivCheck\n\nElixir libraries can define a [private\nAPI](https://hexdocs.pm/elixir/writing-documentation.html#hiding-internal-modules-and-functions)\nby defining a module that is documented as `@moduledoc false`, or a function\nthat is defined as `@doc false`, that module or function should not be called or\nreferenced. PrivCheck is a library to generate warnings when private API's are\ncalled.\n\n## Raison D'etre\n\nIn Elixir it is quite easy to use private API's without realizing, especially if\nthe developer is just copying code from a blog post since there are no warnings\nor errors emitted when using hidden modules. Part of Elixir's philosophy is to\nhelp developers [fall into the pit of\nsuccess](https://blog.codinghorror.com/falling-into-the-pit-of-success/) (e.g.\nmake it easy to do the right thing). So we should make it easy for a developer\nto avoid using the private API's. This library is my attempt to make this\nguideline easy to follow.\n\nThe [usage of private\nAPI's](https://elixirforum.com/t/proposal-private-modules-general-discussion/19374/151)\nhas caused downstream bugs, and resulted in a PSA due to [inadvertant breakage\nin Elixir\nv1.7](https://elixirforum.com/t/psa-do-not-use-private-apis-request-a-feature-instead/15449)\n\nBuilding the concept of Private Modules into the language has been [proposed and\naccepted](https://elixirforum.com/t/proposal-private-modules-general-discussion/19374/143),\nbut it has not yet been implemented.\n\n## Installation\n\nPrivCheck can be installed by adding `priv_check` to your list of dependencies\nin `mix.exs`:\n\n```elixir\ndef deps do\n  [\n    {:priv_check, \"~\u003e 0.2.2\", runtime: false},\n  ]\nend\n```\n\nNext, in your project's `mix.exs` file in your `project` function add\n`:priv_check` to the list of `:compilers` (adding it if it doesn't already\nexist).\n\n```elixir\ndef project do\n  [\n    ...\n    compilers: [:priv_check] ++ Mix.compilers(),\n\n    # If you're using Phoenix it will probably look a little more like this instead:\n    compilers: [:priv_check, :phoenix, :gettext] ++ Mix.compilers(),\n    ...\n  ]\nend\n```\n\nThen run `mix clean` and then `mix compile`\n\n## Configuration\n\nA configuration file can be provided that allows you to configure the behavior\nof PrivCheck. In the root of your repository (same directory that has the\n`mix.exs`) add a `.priv_check.exs` file. Here are some sample contents:\n\n```elixir\n%{\n  # Relative path to files to skip checks for\n  ignored_files: [\"lib/ignored.ex\"],\n\n  # List of modules that are private, but warnings should be ignored\n  ignore_references_to_modules: []\n}\n```\n\n## Nomenclature: Private APIs vs Hidden modules\n\n`@moduledoc false` hides the module from documentation (as implemented in\n[ex_doc](https://github.com/elixir-lang/ex_doc)) which is an indication that the\nmodule should not be used by consumers of the library.\n\n## Usage\n\nAfter following the [installation](#installation) instructions, when you compile\nany code that accesses a private module or function will generate a warning.\n\nHere is a sample warning:\n\n```\nwarning: ExampleDep.Private.add/2 is not a public function\n  and should not be called from other applications.\n  Called from: PrivCheckExample.\n  lib/priv_check_example.ex:21\n```\n\nBecause PrivCheck is a mix compiler, it integrates seamlessly with editors which\ncan work with mix compilers. For example, in VSCode with\n[ElixirLS](https://github.com/elixir-lsp/elixir-ls/):\n\n![Detailed Screnshot of a PrivCheck warning](warning-screenshot.png)\n\nAnd here is how it looks in VSCode's problems list:\n\n![Screenshot of list of problems that PrivCheck raised](warning-problems-screenshot.png)\n\n## How it Works\n\nPrivCheck uses the compiler tracing feature that was released in Elixir v1.10.\nWhen elixir compiles the applications code it keeps a log of all referenced\nmodules and function calls. PrivCheck looks at those modules and functions, and\ninspects their documentation to ascertain if they are hidden modules or\nfunctions, if they are it emits a warning for each violation.\n\n## Limitations\n\nIt is often expected that macro generated code will call hidden functions of its\ncontaining library (for performance reasons). One example of this is\n`Logger.info/2` (v1.9.4) in the standard library will call\n`Logger.__should_log__/2` which is `@doc false`. Since the compiler tracing runs\nafter macros generate code, calling a macro like `Logger.info/2` would result in\na warning since the generated code calls a hidden function. In order to not\nraise false positives on such code, PrivCheck ignores any lines that call a\nremote macro.\n\n## Known Issues\n\n* Returns duplicate-looking warnings [#4](https://github.com/axelson/priv_check/issues/4)\n\n## Related Concepts and Libraries\n\n* Boundary: manage and restrain cross-module dependencies:\n  https://github.com/sasa1977/boundary/\n  * Was an inspiration for much of this library and can be used alongside\n* Dialyzer `@opaque` types: a way to define that a specific struct or datatype\n  should not be used outside of the module that it was defined in.\n  * https://hexdocs.pm/elixir/typespecs.html#user-defined-types\n  * https://hexdocs.pm/elixir/Kernel.html#defstruct/1-types\n* Built-in private modules proposal:\n  https://elixirforum.com/t/proposal-private-modules-general-discussion/19374/1\n* Jose Valim's experiment in adding `defmodulep`: https://github.com/josevalim/defmodulep\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faxelson%2Fpriv_check","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faxelson%2Fpriv_check","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faxelson%2Fpriv_check/lists"}