readme_sync/
lib.rs

1//! The `readme-sync` crate makes it easy to add an integration test
2//! that checks that your readme and crate documentation are synchronized.
3//!
4//! # About
5//!
6//! This crate provides several abstractions for readme and documentation front page content
7//! as well as multiple readme and documentation parsing and transformation functions.
8//! With them, readme and documentation can be converted
9//! to a set of markup nodes that are expected to be the same.
10//! Their equality can be checked with the `assert_sync` function,
11//! which also provides useful diagnostic messages about the differences found.
12//!
13//! Documentation parser accepts not only inner doc-comments (`//!`) but also
14//! inner doc-attributes (`#[!cfg(...)]` and `#[!cfg_attr(...)]`).
15//! This is useful when some doc-tests require certain features to compile and run.
16//!
17//! # Usage
18//!
19//! First, add the following to your `Cargo.toml`:
20//!
21//! ```toml
22//! [dev-dependencies]
23//! readme-sync = "0.3.0"
24//! ```
25//!
26//! Then add an integration test using the necessary readme and docs modifiers,
27//! and check their synchronization using the `assert_sync` function.
28//!
29//! The example below is used to test the synchronization
30//! of the readme and documentation of this crate.
31//! You can copy it and follow the diagnostic messages
32//! to adjust the modifiers used and to correct your readme and documentation.
33//!
34//! ```rust
35//! # /*
36//! #[cfg(test)]
37//! #[test]
38//! fn readme_sync_test() {
39//! # */
40//!     use readme_sync::{assert_sync, CMarkDocs, CMarkReadme, Config, Package};
41//!     use std::borrow::ToOwned;
42//!
43//!     let package = Package::from_path(env!("CARGO_MANIFEST_DIR").into()).unwrap();
44//!     let config = Config::from_package_docs_rs_features(&package);
45//!     let readme = CMarkReadme::from_package(&package).unwrap();
46//!     let docs = CMarkDocs::from_package_and_config(&package, &config).unwrap();
47//!
48//!     let readme = readme
49//!         .remove_badges_paragraph()
50//!         .remove_documentation_section()
51//!         .remove_codeblock_tag("no_sync")
52//!         .disallow_absolute_repository_blob_links()
53//!         .unwrap()
54//!         .use_absolute_repository_blob_urls()
55//!         .unwrap();
56//!
57//!     let docs = docs
58//!         .increment_heading_levels()
59//!         .add_package_title()
60//!         .remove_codeblock_rust_test_tags()
61//!         .use_default_codeblock_rust_tag()
62//!         .remove_hidden_rust_code()
63//!         .map_links(
64//!             |link| match link {
65//!                 "CMarkDocs::map_links" => "struct.CMarkDocs.html#method.map_links".into(),
66//!                 link => link.into(),
67//!             },
68//!             "workaround for intra-doc links",
69//!         )
70//!         .disallow_absolute_package_docs_links()
71//!         .unwrap()
72//!         .use_absolute_package_docs_urls()
73//!         .unwrap();
74//!
75//!     assert_sync(&readme, &docs);
76//! # /*
77//! }
78//! # */
79//! ```
80//!
81//! Note that both `cargo build` and `cargo test` enable features from dev-dependencies,
82//! so if you want to test your crate without them (for example in `no_std` environment)
83//! you can use `readme-sync` with `default-features = false`.
84//! See [this](#how-to-prevent-readme-sync-dependency-features-enabled-for-dependencies-of-my-crate)
85//! FAQ section for more details.
86//!
87//! # Feature Flags
88//!
89//! - `codemap` (enabled by default): Enables `codemap` dependency and required
90//!   for `assert_sync` and other diagnostic functions.
91//! - `codemap-diagnostic` (enabled by default): Enables `codemap-diagnostic` dependency
92//!   and required for `assert_sync` and other diagnostic functions.
93//! - `glob` (enabled by default): Enables `gloc` dependency and required
94//!   for badges detection and methods like `CMarkReadme::remove_badges_paragraph`.
95//! - `platforms`: Enables `platforms` dependency and method `Config::with_target_arch_os_env`.
96//! - `proc-macro2` (enabled by default): Enables `proc-macro2` dependency
97//!   with `span-locations` feature that allows the crate
98//!   to show the errors location for source Rust files.
99//! - `pulldown-cmark` (enabled by default): Enables `pulldown-cmark` dependency
100//!   and required for almost everything except manifest
101//!   and documentation parsing and some utility functions.
102//! - `serde` (enabled by default): Enables `serde` dependency
103//!   and required for manifest deserializing.
104//! - `syn` (enabled by default): Enables `syn` dependency and required for documentation parsing.
105//! - `thiserror` (enabled by default): Enables `thiserror` dependency
106//!   and required by all functions and methods that can return errors.
107//! - `toml` (enabled by default): Enables `toml` dependency and required for manifest parsing.
108//!
109//! # Other crates
110//!
111//! - [`cargo-sync-readme`]: generates readme section from documentation.
112//!   It does not support doc-attributes and does not provide diagnostics for differences found.
113//!   But if you just need to synchronize readme and docs text
114//!   or check if they are synchronized it might be a better choice.
115//! - [`version-sync`]: crate makes it easy to add an integration test that checks
116//!   that README.md and documentation are updated when the crate version changes.
117//!
118//! # FAQ
119//!
120//! ## Are rust intra-doc links supported?
121//!
122//! Currently intra-doc link resolution is not supported.
123//! References to structures in the documentation can be changed with [`CMarkDocs::map_links`].
124//! The pulldown cmark also requires the link address to be specified.
125//!
126//! ## Why is the example integration test so long and there is no function that would do it all at once?
127//!
128//! Readme and documentation transformations are very different
129//! between different crates and the API of this crate is not yet stabilized.
130//!
131//! At the moment, however, it supports extensive customization.
132//! You can specify the paths to readme and docs, their contents,
133//! the features and transformations used, and use your own transformations.
134//!
135//! So any feedback is welcome!
136//!
137//! ## Why use `syn` instead of just parsing documentation comments?
138//!
139//! Because of `cfg` and `cfg_attr` that are useful for documentation tests
140//! that require some specific features and can only be compiled with them.
141//!
142//! ## Why Markdown instead of text comparison?
143//!
144//! It simplifies the Markdown transformations.
145//! Transformations are necessary,
146//! because of some differences between readme content and documentation front page
147//! including: the presence of a crate name, different heading levels,
148//! the presence of badges, different relative url root, etc.
149//!
150//! # License
151//!
152//! Licensed under either of
153//!
154//! - Apache License, Version 2.0
155//!   ([LICENSE-APACHE](https://github.com/zheland/readme-sync/blob/master/LICENSE-APACHE) or
156//!   [https://www.apache.org/licenses/LICENSE-2.0](https://www.apache.org/licenses/LICENSE-2.0))
157//! - MIT license
158//!   ([LICENSE-MIT](https://github.com/zheland/readme-sync/blob/master/LICENSE-MIT) or
159//!   [https://opensource.org/licenses/MIT](https://opensource.org/licenses/MIT))
160//!
161//! at your option.
162//!
163//! ## Contribution
164//!
165//! Unless you explicitly state otherwise, any contribution intentionally submitted
166//! for inclusion in the work by you, as defined in the Apache-2.0 license,
167//! shall be dual licensed as above, without any
168//! additional terms or conditions.
169//!
170//! [`CMarkDocs::map_links`]: CMarkDocs::map_links
171//! [API Documentation]: https://docs.rs/readme-sync
172//! [`cargo-sync-readme`]: https://crates.io/crates/cargo-sync-readme
173//! [`version-sync`]: https://crates.io/crates/version-sync
174
175#![warn(
176    clippy::all,
177    rust_2018_idioms,
178    missing_copy_implementations,
179    missing_debug_implementations,
180    single_use_lifetimes,
181    missing_docs,
182    trivial_casts,
183    unused_import_braces,
184    unused_qualifications,
185    unused_results
186)]
187#![no_std]
188
189extern crate std;
190
191mod badges;
192mod cmark_data;
193mod cmark_docs;
194mod cmark_item;
195mod cmark_readme;
196mod cmark_util;
197mod codemap_files;
198mod codemap_spans;
199mod config;
200mod docs_parser;
201mod file;
202mod file_docs;
203mod manifest;
204mod package;
205mod sync;
206mod tags;
207mod text_source;
208
209pub use badges::badge_url_patterns;
210pub use cmark_data::{CMarkData, CMarkDataIter, DisallowUrlsWithPrefixError};
211pub use cmark_docs::CMarkDocs;
212pub use cmark_item::{
213    CMarkItem, CMarkItemAsModified, CMarkItemAsRemoved, CMarkItemWithNote, CMarkSpan,
214};
215pub use cmark_readme::{CMarkReadme, CMarkReadmeFromPackageError};
216pub use codemap_files::CodemapFiles;
217pub use codemap_spans::CodemapSpans;
218pub use config::Config;
219pub use docs_parser::{
220    build_attr_docs, build_meta_docs, eval_cfg_predicate, BuildAttrDocsError, BuildMetaDocsError,
221    EvalCfgPredicateError,
222};
223pub use docs_parser::{DocsItem, DocsSpan};
224pub use file::{File, FileFromPathError};
225pub use file_docs::{FileDocs, FileDocsFromFileError, TextRemap};
226pub use manifest::{
227    BinPathError, Manifest, ManifestBinTarget, ManifestDocsRsMetadata, ManifestLibTarget,
228    ManifestPackage, ManifestReadmePath, TomlParseError, TomlReadError,
229};
230pub use package::Package;
231pub use sync::{assert_sync, check_sync, CheckSyncError, MatchFailed};
232pub use tags::codeblock_rust_test_tags;
233pub use text_source::TextSource;
234
235use cmark_util::IntoStatic;