Skip to content

Commit 61a4720

Browse files
Docs Gen Tool Updates (#2012)
Many updates to the docs gen tool: - Generates docs for `@Config(Unrestricted)` items. - Moves Unstable namespaces to the bottom of the Table of Contents. - Generates docs for reexported Core items. - Generates index.md files for namespaces. - Generates a top-level index.md file. - Trims datetime to just be the date. - Adds description metadata field. fixes #1998 fixes #1866
1 parent 093ccfe commit 61a4720

File tree

9 files changed

+618
-183
lines changed

9 files changed

+618
-183
lines changed

compiler/qsc_doc_gen/src/generate_docs.rs

+393-169
Large diffs are not rendered by default.

compiler/qsc_doc_gen/src/generate_docs/tests.rs

+165-2
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,19 @@ use super::generate_docs;
55
use expect_test::expect;
66

77
#[test]
8-
fn docs_generation() {
8+
fn generates_standard_item() {
99
let files = generate_docs(None, None, None);
1010
let (_, metadata, contents) = files
1111
.iter()
1212
.find(|(file_name, _, _)| &**file_name == "Std.Core/Length.md")
13-
.expect("Could not file doc file for Length");
13+
.expect("Could not find doc file for Length");
1414
let full_contents = format!("{metadata}\n\n{contents}");
1515

1616
expect![[r#"
1717
---
1818
uid: Qdk.Std.Core.Length
1919
title: Length function
20+
description: "Q# Length function: Returns the number of elements in the input array `a`."
2021
ms.date: {TIMESTAMP}
2122
ms.topic: managed-reference
2223
qsharp.kind: function
@@ -51,3 +52,165 @@ fn docs_generation() {
5152
"#]]
5253
.assert_eq(full_contents.as_str());
5354
}
55+
56+
#[test]
57+
fn generates_unrestricted_item() {
58+
let files = generate_docs(None, None, None);
59+
let (_, metadata, contents) = files
60+
.iter()
61+
.find(|(file_name, _, _)| &**file_name == "Std.Diagnostics/CheckZero.md")
62+
.expect("Could not file doc file for CheckZero");
63+
let full_contents = format!("{metadata}\n\n{contents}");
64+
65+
expect![[r#"
66+
---
67+
uid: Qdk.Std.Diagnostics.CheckZero
68+
title: CheckZero operation
69+
description: "Q# CheckZero operation: Checks whether a qubit is in the \|0⟩ state, returning true if it is."
70+
ms.date: {TIMESTAMP}
71+
ms.topic: managed-reference
72+
qsharp.kind: operation
73+
qsharp.package: __Std__
74+
qsharp.namespace: Std.Diagnostics
75+
qsharp.name: CheckZero
76+
qsharp.summary: "Checks whether a qubit is in the \|0⟩ state, returning true if it is."
77+
---
78+
79+
# CheckZero operation
80+
81+
Fully qualified name: Std.Diagnostics.CheckZero
82+
83+
```qsharp
84+
operation CheckZero(qubit : Qubit) : Bool
85+
```
86+
87+
## Summary
88+
Checks whether a qubit is in the |0⟩ state, returning true if it is.
89+
90+
## Description
91+
This operation checks whether a qubit is in the |0⟩ state. It will return true only
92+
if the qubit is deterministically in the |0⟩ state, and will return false otherwise. This operation
93+
does not change the state of the qubit.
94+
95+
## Input
96+
### qubit
97+
The qubit to check.
98+
## Output
99+
True if the qubit is in the |0⟩ state, false otherwise.
100+
101+
## Remarks
102+
This operation is useful for checking whether a qubit is in the |0⟩ state during simulation. It is not possible to check
103+
this on hardware without measuring the qubit, which could change the state.
104+
"#]]
105+
.assert_eq(full_contents.as_str());
106+
}
107+
108+
#[test]
109+
fn redirect_generation() {
110+
let files = generate_docs(None, None, None);
111+
let (_, metadata, contents) = files
112+
.iter()
113+
.find(|(file_name, _, _)| &**file_name == "Microsoft.Quantum.Core/Length.md")
114+
.expect("Could not find doc file for Length");
115+
let full_contents = format!("{metadata}\n\n{contents}");
116+
117+
expect![[r#"
118+
---
119+
uid: Qdk.Microsoft.Quantum.Core.Length
120+
title: Length exported item
121+
description: "Q# Length exported item: This is an exported item. The actual definition is found here: [Length](xref:Qdk.Std.Core.Length)"
122+
ms.date: {TIMESTAMP}
123+
ms.topic: managed-reference
124+
qsharp.kind: export
125+
qsharp.package: __Std__
126+
qsharp.namespace: Microsoft.Quantum.Core
127+
qsharp.name: Length
128+
qsharp.summary: "This is an exported item. The actual definition is found here: [Length](xref:Qdk.Std.Core.Length)"
129+
---
130+
131+
# Length exported item
132+
133+
Fully qualified name: Microsoft.Quantum.Core.Length
134+
135+
This is an exported item. The actual definition is found here: [Length](xref:Qdk.Std.Core.Length)
136+
"#]]
137+
.assert_eq(full_contents.as_str());
138+
}
139+
140+
#[test]
141+
fn index_file_generation() {
142+
let files = generate_docs(None, None, None);
143+
let (_, metadata, contents) = files
144+
.iter()
145+
.find(|(file_name, _, _)| &**file_name == "Std.Core/index.md")
146+
.expect("Could not find Std.Core Table of Contents file");
147+
let full_contents = format!("{metadata}\n\n{contents}");
148+
149+
expect![[r#"
150+
---
151+
uid: Qdk.Std.Core-toc
152+
title: Std.Core namespace
153+
description: Table of contents for the Q# Core namespace
154+
author: {AUTHOR}
155+
ms.author: {MS_AUTHOR}
156+
ms.date: {TIMESTAMP}
157+
ms.topic: landing-page
158+
---
159+
160+
# Std.Core
161+
162+
The Std.Core namespace contains the following items:
163+
164+
| Name | Description |
165+
|------|-------------|
166+
| [Length](xref:Qdk.Std.Core.Length) | Returns the number of elements in the input array `a`. |
167+
| [Repeated](xref:Qdk.Std.Core.Repeated) | Creates an array of given `length` with all elements equal to given `value`. `length` must be a non-negative integer. |
168+
"#]]
169+
.assert_eq(full_contents.as_str());
170+
}
171+
172+
#[test]
173+
fn top_index_file_generation() {
174+
let files = generate_docs(None, None, None);
175+
let (_, metadata, contents) = files
176+
.iter()
177+
.find(|(file_name, _, _)| &**file_name == "index.md")
178+
.expect("Could not find top-level Table of Contents file");
179+
let full_contents = format!("{metadata}\n\n{contents}");
180+
181+
expect![[r#"
182+
---
183+
uid: Microsoft.Quantum.apiref-toc
184+
title: Q# standard libraries for the Azure Quantum Development Kit
185+
description: Table of contents for the Q# standard libraries for Azure Quantum Development Kit
186+
author: {AUTHOR}
187+
ms.author: {MS_AUTHOR}
188+
ms.date: {TIMESTAMP}
189+
ms.topic: landing-page
190+
---
191+
192+
# Q# standard library
193+
194+
The Q# standard library contains the following namespaces:
195+
196+
| Namespace | Description |
197+
| --------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ |
198+
| [`Microsoft.Quantum.Core`](xref:Qdk.Microsoft.Quantum.Core-toc) | Re-exported functions. |
199+
| [`Std.Arrays`](xref:Qdk.Std.Arrays-toc) | Items for working with arrays. |
200+
| [`Std.Canon`](xref:Qdk.Std.Canon-toc) | Canonical implementations of common classical and quantum utilities.|
201+
| [`Std.Convert`](xref:Qdk.Std.Convert-toc) | Items for converting between different types. |
202+
| [`Std.Core`](xref:Qdk.Std.Core-toc) | Items for language built-in operations. |
203+
| [`Std.Diagnostics`](xref:Qdk.Std.Diagnostics-toc) | Items for debugging and testing quantum programs. |
204+
| [`Std.Intrinsic`](xref:Qdk.Std.Intrinsic-toc) | Items that provide core quantum operations. |
205+
| [`Std.Logical`](xref:Qdk.Std.Logical-toc) | Boolean Logic functions. |
206+
| [`Std.Math`](xref:Qdk.Std.Math-toc) | Items for classical math operations. |
207+
| [`Std.Measurement`](xref:Qdk.Std.Measurement-toc) | Items for measuring quantum results. |
208+
| [`Std.Random`](xref:Qdk.Std.Random-toc) | Items for creating random values. |
209+
| [`Std.Range`](xref:Qdk.Std.Range-toc) | Items for working with ranges. |
210+
| [`Std.ResourceEstimation`](xref:Qdk.Std.ResourceEstimation-toc) | Items for working with the Azure Quantum Resource Estimator. |
211+
| [`Microsoft.Quantum.Unstable.Arithmetic`](xref:Qdk.Microsoft.Quantum.Unstable.Arithmetic-toc) | Items for working with quantum arithmetic operations. |
212+
| [`Microsoft.Quantum.Unstable.StatePreparation`](xref:Qdk.Microsoft.Quantum.Unstable.StatePreparation-toc) | Items for preparing a quantum state. |
213+
| [`Microsoft.Quantum.Unstable.TableLookup`](xref:Qdk.Microsoft.Quantum.Unstable.TableLookup-toc) | Items for performing quantum table lookups. |
214+
"#]]
215+
.assert_eq(full_contents.as_str());
216+
}

compiler/qsc_doc_gen/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@
33

44
pub mod display;
55
pub mod generate_docs;
6+
mod table_of_contents;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
/// Returns the string of the table of contents for the standard library.
5+
/// This table of contents will be the content of the top-level index.md
6+
/// created during documentation generation.
7+
pub(super) fn table_of_contents() -> String {
8+
"# Q# standard library
9+
10+
The Q# standard library contains the following namespaces:
11+
12+
| Namespace | Description |
13+
| --------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ |
14+
| [`Microsoft.Quantum.Core`](xref:Qdk.Microsoft.Quantum.Core-toc) | Re-exported functions. |
15+
| [`Std.Arrays`](xref:Qdk.Std.Arrays-toc) | Items for working with arrays. |
16+
| [`Std.Canon`](xref:Qdk.Std.Canon-toc) | Canonical implementations of common classical and quantum utilities.|
17+
| [`Std.Convert`](xref:Qdk.Std.Convert-toc) | Items for converting between different types. |
18+
| [`Std.Core`](xref:Qdk.Std.Core-toc) | Items for language built-in operations. |
19+
| [`Std.Diagnostics`](xref:Qdk.Std.Diagnostics-toc) | Items for debugging and testing quantum programs. |
20+
| [`Std.Intrinsic`](xref:Qdk.Std.Intrinsic-toc) | Items that provide core quantum operations. |
21+
| [`Std.Logical`](xref:Qdk.Std.Logical-toc) | Boolean Logic functions. |
22+
| [`Std.Math`](xref:Qdk.Std.Math-toc) | Items for classical math operations. |
23+
| [`Std.Measurement`](xref:Qdk.Std.Measurement-toc) | Items for measuring quantum results. |
24+
| [`Std.Random`](xref:Qdk.Std.Random-toc) | Items for creating random values. |
25+
| [`Std.Range`](xref:Qdk.Std.Range-toc) | Items for working with ranges. |
26+
| [`Std.ResourceEstimation`](xref:Qdk.Std.ResourceEstimation-toc) | Items for working with the Azure Quantum Resource Estimator. |
27+
| [`Microsoft.Quantum.Unstable.Arithmetic`](xref:Qdk.Microsoft.Quantum.Unstable.Arithmetic-toc) | Items for working with quantum arithmetic operations. |
28+
| [`Microsoft.Quantum.Unstable.StatePreparation`](xref:Qdk.Microsoft.Quantum.Unstable.StatePreparation-toc) | Items for preparing a quantum state. |
29+
| [`Microsoft.Quantum.Unstable.TableLookup`](xref:Qdk.Microsoft.Quantum.Unstable.TableLookup-toc) | Items for performing quantum table lookups. |
30+
".to_string()
31+
}

library/std/src/Std/Math.qs

+2
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,8 @@ function AbsD(a : Double) : Double {
160160
a < 0.0 ? -a | a
161161
}
162162

163+
/// # Summary
164+
/// Returns the absolute value of a big integer.
163165
function AbsL(a : BigInt) : BigInt {
164166
a < 0L ? -a | a
165167
}

npm/qsharp/generate_docs.js

+11-6
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,15 @@ var today = new Date();
3131
var dd = String(today.getDate()).padStart(2, "0");
3232
var mm = String(today.getMonth() + 1).padStart(2, "0"); //January is 0!
3333
var yyyy = today.getFullYear();
34-
var today_str = mm + "/" + dd + "/" + yyyy + " 12:00:00 AM";
34+
var today_str = mm + "/" + dd + "/" + yyyy;
3535

3636
docs.forEach((doc) => {
3737
// If the filename contains a /, then we need to create the directory
3838
const parts = doc.filename.split("/");
3939
let fullPath = "";
4040
switch (parts.length) {
4141
case 1:
42-
if (doc.filename !== "toc.yml") {
42+
if (doc.filename !== "toc.yml" && doc.filename !== "index.md") {
4343
throw new Error(`Invalid filename: ${doc.filename}`);
4444
} else {
4545
fullPath = join(docsDirPath, doc.filename);
@@ -57,10 +57,15 @@ docs.forEach((doc) => {
5757
default:
5858
throw new Error(`Invalid file path: ${doc.filename}`);
5959
}
60-
var contents =
61-
doc.metadata.replace("ms.date: {TIMESTAMP}", `ms.date: ${today_str}`) +
62-
"\n\n" +
63-
doc.contents;
60+
var contents = "";
61+
if (doc.filename === "toc.yml") {
62+
contents = doc.contents;
63+
} else {
64+
contents =
65+
doc.metadata.replace("ms.date: {TIMESTAMP}", `ms.date: ${today_str}`) +
66+
"\n\n" +
67+
doc.contents;
68+
}
6469
writeFileSync(fullPath, contents);
6570
});
6671

npm/qsharp/test/basics.js

+3
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ test("autogenerated documentation", async () => {
5151
var numberOfGoodFiles = 0;
5252
for (const doc of docFiles) {
5353
assert(doc, "Each documentation file should be present.");
54+
if (doc.filename === "index.md") {
55+
continue; // Skip index.md - its contents are added later
56+
}
5457
assert(
5558
doc.contents && doc.contents.length > 10,
5659
"Content for each documentation file should be present.",

playground/src/docs.tsx

+5-2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@ export function processDocumentFiles(
2020
docFiles: IDocFile[],
2121
): Map<string, string> {
2222
const contentByNamespace = new Map<string, string>();
23-
const regex = new RegExp("^qsharp.namespace: Microsoft.Quantum.(.+)$", "m");
23+
const regex = new RegExp(
24+
"^qsharp\\.namespace: (Microsoft\\.Quantum|Std)\\.(.+)$",
25+
"m",
26+
);
2427

2528
for (const doc of docFiles) {
2629
const match = regex.exec(doc.metadata); // Parse namespace out of metadata
@@ -29,7 +32,7 @@ export function processDocumentFiles(
2932
}
3033
// The next line contains "Zero-width space" unicode character
3134
// to allow line breaks before the period.
32-
const newNamespace = "… " + match[1].replace(".", "​.");
35+
const newNamespace = "… " + match[2].replace(".", "​.");
3336

3437
if (contentByNamespace.has(newNamespace)) {
3538
const existingContent = contentByNamespace.get(newNamespace)!;

wasm/src/tests.rs

+7-4
Original file line numberDiff line numberDiff line change
@@ -504,17 +504,20 @@ fn test_doc_gen() {
504504
let docs = qsc_doc_gen::generate_docs::generate_docs(None, None, None);
505505
assert!(docs.len() > 100);
506506
for (name, metadata, contents) in docs {
507-
// filename will be something like "Microsoft.Quantum.Canon/ApplyToEachC.md"
507+
// filename will be something like "Std.Canon/ApplyToEachC.md"
508508
let filename = name.to_string();
509509
// Text is the full markdown including initial metadata inside '---' blocks
510510
let text = format!("{metadata}\n\n{contents}");
511511
if filename.eq("toc.yml") {
512-
assert!(text.contains("uid: Qdk.Microsoft.Quantum.Core"));
513-
} else {
512+
assert!(text.contains("uid: Qdk.Std.Core"));
513+
} else if !filename.eq("index.md") {
514514
assert!(std::path::Path::new(&filename)
515515
.extension()
516516
.map_or(false, |ext| ext.eq_ignore_ascii_case("md")));
517-
assert!(text.starts_with("---\n"));
517+
assert!(
518+
text.starts_with("---\n"),
519+
"file {name} does not start with metadata\ncontents: {text}"
520+
);
518521
}
519522
}
520523
}

0 commit comments

Comments
 (0)