mirror of https://github.com/Qiskit/qiskit.org.git
Autogenerate textbook TOC (#103)
* Change to nuxt-ts to support TypeScript at build time * Add jest infrastructure * Automatize creation of content/education/textbook-toc.md for /education preview * Test the functionality
This commit is contained in:
parent
f7b0a47703
commit
c810752dc6
|
@ -7,6 +7,11 @@ module.exports = {
|
||||||
'@nuxtjs'
|
'@nuxtjs'
|
||||||
],
|
],
|
||||||
rules: {
|
rules: {
|
||||||
|
// TODO: Remove when fixing:
|
||||||
|
// https://github.com/typescript-eslint/typescript-eslint/issues/342
|
||||||
|
// More info:
|
||||||
|
// https://github.com/typescript-eslint/typescript-eslint/issues/342#issuecomment-484739065
|
||||||
|
'no-undef': 'off',
|
||||||
'@typescript-eslint/no-unused-vars': 'error'
|
'@typescript-eslint/no-unused-vars': 'error'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,8 @@
|
||||||
## Table of Contents
|
## Table of Contents
|
||||||
|
|
||||||
### Preface
|
|
||||||
- Structure of this Textbook
|
|
||||||
|
|
||||||
### Chapter 0. Prerequisites
|
### Chapter 0. Prerequisites
|
||||||
- Python and Jupyter Notebooks
|
- Python and Jupyter Notebooks
|
||||||
- Qiskit
|
- Qiskit
|
||||||
- Exercises
|
- Linear Algebra
|
||||||
|
|
||||||
### Chapter 1. Quantum States and Qubits
|
### Chapter 1. Quantum States and Qubits
|
||||||
- Introduction
|
- Introduction
|
||||||
- The Atoms of Computation
|
- The Atoms of Computation
|
||||||
|
@ -15,8 +10,6 @@
|
||||||
- Writing Down Qubit States
|
- Writing Down Qubit States
|
||||||
- Pauli Matrices and the Bloch Sphere
|
- Pauli Matrices and the Bloch Sphere
|
||||||
- States for Many Qubits
|
- States for Many Qubits
|
||||||
- Exercises
|
|
||||||
|
|
||||||
### Chapter 2. Single-Qubit and Multi-Qubit Gates
|
### Chapter 2. Single-Qubit and Multi-Qubit Gates
|
||||||
- Introduction
|
- Introduction
|
||||||
- Quantum Gates
|
- Quantum Gates
|
||||||
|
@ -24,8 +17,6 @@
|
||||||
- The Standard Gate Set
|
- The Standard Gate Set
|
||||||
- Proving Universality
|
- Proving Universality
|
||||||
- Basic Circuit Identities
|
- Basic Circuit Identities
|
||||||
- Exercises
|
|
||||||
|
|
||||||
### Chapter 3. Quantum Algorithms
|
### Chapter 3. Quantum Algorithms
|
||||||
- Quantum Teleportation
|
- Quantum Teleportation
|
||||||
- Deutsch-Josza Algorithm
|
- Deutsch-Josza Algorithm
|
||||||
|
@ -34,17 +25,14 @@
|
||||||
- Quantum Fourier Transform
|
- Quantum Fourier Transform
|
||||||
- Quantum Phase Estimation
|
- Quantum Phase Estimation
|
||||||
- Grover's Algorithm
|
- Grover's Algorithm
|
||||||
- Exercises
|
|
||||||
|
|
||||||
### Chapter 4. Quantum Algorithms for Applications
|
### Chapter 4. Quantum Algorithms for Applications
|
||||||
- Simulating Molecules using VQE
|
- Simulating Molecules using VQE
|
||||||
- Solving Satisfiability Problems using Grover's Algorithm
|
- Solving Satisfiability Problems using Grover's Algorithm
|
||||||
- Exercises
|
|
||||||
|
|
||||||
### Chapter 5. Investigating Quantum Hardware Using Qiskit
|
### Chapter 5. Investigating Quantum Hardware Using Qiskit
|
||||||
- Calibrating Qubits with OpenPulse
|
- Calibrating Qubits with OpenPulse
|
||||||
- Introduction to Quantum Error Correction using Repetition Codes
|
- Introduction to Quantum Error Correction using Repetition Codes
|
||||||
- Measurement Error Mitigation
|
- Measurement Error Mitigation
|
||||||
- Randomized Benchmarking
|
- Randomized Benchmarking
|
||||||
- Measuring Quantum Volume
|
- Measuring Quantum Volume
|
||||||
- Exercises
|
### Chapter 6. Implementations of Recent Quantum Algorithms
|
||||||
|
- Variational Quantum Linear Solver
|
|
@ -0,0 +1,16 @@
|
||||||
|
import fs from 'fs'
|
||||||
|
import { extractToc, formatTocLines } from './textbook-toc-utils'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract the table of contents at `indexPath` and uses it to generate
|
||||||
|
* a markdown TOC at `tocPath`, suitable for being rendered in `/education`.
|
||||||
|
*
|
||||||
|
* @param indexPath HTML file where the TOC is extracted from.
|
||||||
|
* @param tocPath output Markdown file path where TOC is generated.
|
||||||
|
*/
|
||||||
|
export default function generateTextbookToc(indexPath: string, tocPath: string) {
|
||||||
|
const indexContent = fs.readFileSync(indexPath, 'utf8')
|
||||||
|
const toc = extractToc(indexContent)
|
||||||
|
const mdTocLines = formatTocLines(toc)
|
||||||
|
fs.writeFileSync(tocPath, mdTocLines.join('\n'))
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
type TocType = Array<[string, string[]]>
|
||||||
|
|
||||||
|
export { extractToc, formatTocLines, TocType }
|
||||||
|
|
||||||
|
function extractToc(indexContent: string): TocType {
|
||||||
|
// Chapter titles are of form `Chapter X. Chapter title<`.
|
||||||
|
const allChapters = (indexContent.match(/Chapter\s+\d+\.\s+[^<]+/g) || [])
|
||||||
|
.map(entry => entry.trim())
|
||||||
|
// Topic titles are of form `X.Y <a ...>Topic Title<`
|
||||||
|
const allTopics = (indexContent.match(/(\d+.\d+\s+)<a[^>]+([^<]+)/g) || [])
|
||||||
|
.map(entry => entry.replace(/<a[^>]+>/, '').trim())
|
||||||
|
|
||||||
|
return allChapters.reduce<TocType>((output, title, index) => {
|
||||||
|
const chapters = getTopics(index, allTopics)
|
||||||
|
output.push([title, chapters])
|
||||||
|
return output
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
function getTopics(index: number, allTopics: string[]) {
|
||||||
|
return allTopics.filter(topic => topic.startsWith(`${index}.`))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatTocLines(toc: TocType, header: string = 'Table of Contents'): string[] {
|
||||||
|
return withHeader(
|
||||||
|
header,
|
||||||
|
toc.reduce<string[]>((output, [title, chapters]) => {
|
||||||
|
output.push(formatTitle(title))
|
||||||
|
output.push(...formatChapters(chapters))
|
||||||
|
return output
|
||||||
|
}, [])
|
||||||
|
)
|
||||||
|
|
||||||
|
function withHeader(title: string, lines: string[]): string[] {
|
||||||
|
lines.unshift(`## ${title}`)
|
||||||
|
return lines
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatTitle(title: string): string {
|
||||||
|
return `### ${title}`
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatChapters(chapters: string[]): string[] {
|
||||||
|
return chapters
|
||||||
|
.map(title => `- ${(title.match(/\s.+/) as string[])[0].trim()}`)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
// Created following:
|
||||||
|
// https://github.com/Al-un/learn-nuxt-ts/blob/master/docs/06.test.md
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
moduleNameMapper: {
|
||||||
|
'^@/(.*)$': '<rootDir>/$1',
|
||||||
|
'^~/(.*)$': '<rootDir>/$1'
|
||||||
|
},
|
||||||
|
transform: {
|
||||||
|
'^.+\\.ts?$': 'ts-jest',
|
||||||
|
'.*\\.(vue)$': 'vue-jest'
|
||||||
|
},
|
||||||
|
moduleFileExtensions: ['ts', 'js', 'vue', 'json'],
|
||||||
|
testMatch: ['**/tests/**/*.spec.ts'],
|
||||||
|
collectCoverageFrom: [
|
||||||
|
'hooks/**/*.ts'
|
||||||
|
]
|
||||||
|
}
|
|
@ -5,6 +5,7 @@ import miLinkAttributes from 'markdown-it-link-attributes'
|
||||||
import miAnchor from 'markdown-it-anchor'
|
import miAnchor from 'markdown-it-anchor'
|
||||||
import uslug from 'uslug'
|
import uslug from 'uslug'
|
||||||
import pkg from './package'
|
import pkg from './package'
|
||||||
|
import generateTextbookToc from './hooks/generate-textbook-toc'
|
||||||
|
|
||||||
const md = markdownIt({
|
const md = markdownIt({
|
||||||
linkify: true,
|
linkify: true,
|
||||||
|
@ -162,5 +163,16 @@ export default {
|
||||||
.map(filename => `/experiments/${path.parse(filename).name}`)
|
.map(filename => `/experiments/${path.parse(filename).name}`)
|
||||||
return events.concat(experiments)
|
return events.concat(experiments)
|
||||||
})()
|
})()
|
||||||
|
},
|
||||||
|
|
||||||
|
hooks: {
|
||||||
|
build: {
|
||||||
|
before() {
|
||||||
|
generateTextbookToc(
|
||||||
|
'./static/textbook/index.html',
|
||||||
|
'./content/education/textbook-toc.md'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
17
package.json
17
package.json
|
@ -5,12 +5,12 @@
|
||||||
"author": "IBM Q Community Team",
|
"author": "IBM Q Community Team",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "nuxt",
|
"dev": "nuxt-ts",
|
||||||
"dev-debug": "node --debug node_modules/.bin/nuxt",
|
"dev-debug": "node --debug node_modules/.bin/nuxt-ts",
|
||||||
"test": "echo \"Error: no test specified\" && exit 0",
|
"test": "jest",
|
||||||
"build": "npm run generate",
|
"build": "npm run generate",
|
||||||
"start": "nuxt start",
|
"start": "nuxt-ts start",
|
||||||
"generate": "nuxt generate",
|
"generate": "nuxt-ts generate",
|
||||||
"lint": "eslint --ext .ts,.js,.vue --ignore-path .gitignore ."
|
"lint": "eslint --ext .ts,.js,.vue --ignore-path .gitignore ."
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -22,9 +22,13 @@
|
||||||
"@nuxt/typescript-build": "^0.1.11",
|
"@nuxt/typescript-build": "^0.1.11",
|
||||||
"@nuxt/typescript-runtime": "^0.1.5",
|
"@nuxt/typescript-runtime": "^0.1.5",
|
||||||
"@nuxtjs/eslint-config": "0.0.1",
|
"@nuxtjs/eslint-config": "0.0.1",
|
||||||
|
"@types/jest": "^24.0.20",
|
||||||
"@types/markdown-it": "0.0.7",
|
"@types/markdown-it": "0.0.7",
|
||||||
"@typescript-eslint/eslint-plugin": "^1.13.0",
|
"@typescript-eslint/eslint-plugin": "^1.13.0",
|
||||||
"@typescript-eslint/parser": "^1.13.0",
|
"@typescript-eslint/parser": "^1.13.0",
|
||||||
|
"@vue/test-utils": "^1.0.0-beta.29",
|
||||||
|
"babel-bridge": "^1.12.11",
|
||||||
|
"babel-core": "^6.26.3",
|
||||||
"d3": "^5.11.0",
|
"d3": "^5.11.0",
|
||||||
"datamaps": "github:delapuente/datamaps#0.5.10",
|
"datamaps": "github:delapuente/datamaps#0.5.10",
|
||||||
"eslint": "^5.16.0",
|
"eslint": "^5.16.0",
|
||||||
|
@ -36,13 +40,16 @@
|
||||||
"eslint-plugin-standard": "^4.0.1",
|
"eslint-plugin-standard": "^4.0.1",
|
||||||
"eslint-plugin-vue": "^5.2.3",
|
"eslint-plugin-vue": "^5.2.3",
|
||||||
"frontmatter-markdown-loader": "^1.8.0",
|
"frontmatter-markdown-loader": "^1.8.0",
|
||||||
|
"jest": "^24.9.0",
|
||||||
"markdown-it-anchor": "^5.2.4",
|
"markdown-it-anchor": "^5.2.4",
|
||||||
"markdown-it-link-attributes": "^2.1.0",
|
"markdown-it-link-attributes": "^2.1.0",
|
||||||
"node-sass": "^4.12.0",
|
"node-sass": "^4.12.0",
|
||||||
"nodemon": "^1.19.2",
|
"nodemon": "^1.19.2",
|
||||||
"sass-loader": "^8.0.0",
|
"sass-loader": "^8.0.0",
|
||||||
"topojson": "^3.0.2",
|
"topojson": "^3.0.2",
|
||||||
|
"ts-jest": "^24.1.0",
|
||||||
"uslug": "^1.0.4",
|
"uslug": "^1.0.4",
|
||||||
|
"vue-jest": "^3.0.5",
|
||||||
"vue-property-decorator": "^8.2.2"
|
"vue-property-decorator": "^8.2.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
import { extractToc, formatTocLines, TocType } from '~/hooks/textbook-toc-utils'
|
||||||
|
|
||||||
|
const sampleHTML = `<p><strong>Chapter 0. Title 0</strong><br /></p>
|
||||||
|
<p> 0.0 <a href="./ch-prerequisites/python-and-jupyter-notebooks.html">Topic 0.0</a><br />
|
||||||
|
0.1 <a href="./ch-prerequisites/qiskit.html">Topic 0.1</a><br />
|
||||||
|
<p><strong>Chapter 1. Title 1</strong><br /></p>
|
||||||
|
<p> 1.0 <a href="./ch-states/introduction.html">Topic 1.0</a><br />
|
||||||
|
1.1 <a href="./ch-states/atoms-computation.html">Topic 1.1</a><br />`
|
||||||
|
|
||||||
|
const expectedToc: TocType = [
|
||||||
|
['Chapter 0. Title 0', [
|
||||||
|
'0.0 Topic 0.0',
|
||||||
|
'0.1 Topic 0.1'
|
||||||
|
]],
|
||||||
|
['Chapter 1. Title 1', [
|
||||||
|
'1.0 Topic 1.0',
|
||||||
|
'1.1 Topic 1.1'
|
||||||
|
]]
|
||||||
|
]
|
||||||
|
|
||||||
|
describe('extractToc', () => {
|
||||||
|
it('recognizes and matches chapters and topics', () => {
|
||||||
|
expect(extractToc(sampleHTML)).toEqual(expectedToc)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('formatTocLines', () => {
|
||||||
|
it('generates a simplified markdown version of the toc', () => {
|
||||||
|
expect(formatTocLines(expectedToc, 'Title')).toEqual([
|
||||||
|
'## Title',
|
||||||
|
'### Chapter 0. Title 0',
|
||||||
|
'- Topic 0.0',
|
||||||
|
'- Topic 0.1',
|
||||||
|
'### Chapter 1. Title 1',
|
||||||
|
'- Topic 1.0',
|
||||||
|
'- Topic 1.1'
|
||||||
|
])
|
||||||
|
})
|
||||||
|
})
|
|
@ -26,7 +26,8 @@
|
||||||
},
|
},
|
||||||
"types": [
|
"types": [
|
||||||
"@types/node",
|
"@types/node",
|
||||||
"@nuxt/types"
|
"@nuxt/types",
|
||||||
|
"@types/jest"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"exclude": [
|
"exclude": [
|
||||||
|
|
Loading…
Reference in New Issue