@abreen/tada 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +290 -0
  3. package/bin/tada.js +361 -0
  4. package/config/authors.json +1 -0
  5. package/config/nav.json +28 -0
  6. package/content/index.md +19 -0
  7. package/content/lectures/01/Pair.java.md +296 -0
  8. package/content/lectures/01/Rectangle.java +80 -0
  9. package/content/lectures/01/demo.py +9 -0
  10. package/content/lectures/01/index.md +39 -0
  11. package/content/lectures/01/lecture1.pdf +0 -0
  12. package/content/lectures/index.md +25 -0
  13. package/content/markdown.md +379 -0
  14. package/content/problem_sets/index.md +6 -0
  15. package/fonts/google-sans-code/GoogleSansCodeVariable-Italic.ttf +0 -0
  16. package/fonts/google-sans-code/GoogleSansCodeVariable.ttf +0 -0
  17. package/fonts/google-sans-code/LICENSE.txt +93 -0
  18. package/fonts/inter/InterVariable-Italic.ttf +0 -0
  19. package/fonts/inter/InterVariable.ttf +0 -0
  20. package/fonts/inter/LICENSE.txt +92 -0
  21. package/package.json +70 -0
  22. package/public/avatars/alex.jpg +0 -0
  23. package/public/test.txt +1 -0
  24. package/src/_mixins.scss +4 -0
  25. package/src/anchor/README.md +6 -0
  26. package/src/anchor/index.ts +34 -0
  27. package/src/anchor/style.scss +48 -0
  28. package/src/code/README.md +5 -0
  29. package/src/code/index.ts +113 -0
  30. package/src/code/style.scss +101 -0
  31. package/src/code.scss +54 -0
  32. package/src/header/README.md +8 -0
  33. package/src/header/index.ts +43 -0
  34. package/src/header/style.scss +228 -0
  35. package/src/index.ts +73 -0
  36. package/src/layout.scss +144 -0
  37. package/src/literate/style.scss +60 -0
  38. package/src/print/README.md +4 -0
  39. package/src/print/index.ts +32 -0
  40. package/src/print/style.scss +82 -0
  41. package/src/question/README.md +3 -0
  42. package/src/question/index.ts +25 -0
  43. package/src/question/style.scss +116 -0
  44. package/src/search/README.md +6 -0
  45. package/src/search/index.ts +574 -0
  46. package/src/search/style.scss +217 -0
  47. package/src/style.scss +815 -0
  48. package/src/timezone/index.test.ts +100 -0
  49. package/src/timezone/index.ts +298 -0
  50. package/src/timezone/style.scss +16 -0
  51. package/src/timezone/timezones.json +58 -0
  52. package/src/toc/README.md +3 -0
  53. package/src/toc/index.ts +322 -0
  54. package/src/toc/style.scss +203 -0
  55. package/src/top/README.md +4 -0
  56. package/src/top/index.ts +75 -0
  57. package/src/util.ts +122 -0
  58. package/templates/_author.html +27 -0
  59. package/templates/_bottom.html +3 -0
  60. package/templates/_download.html +1 -0
  61. package/templates/_heading.html +19 -0
  62. package/templates/_nav.html +18 -0
  63. package/templates/_theme.scss +97 -0
  64. package/templates/_top.html +87 -0
  65. package/templates/authors.schema.json +13 -0
  66. package/templates/code.html +31 -0
  67. package/templates/default.html +13 -0
  68. package/templates/literate.html +16 -0
  69. package/templates/nav.schema.json +27 -0
  70. package/tsconfig.json +15 -0
  71. package/types/dev.ts +3 -0
  72. package/types/sass.d.ts +1 -0
  73. package/types/site-variables.d.ts +16 -0
  74. package/webpack/apply-base-path-plugin.js +78 -0
  75. package/webpack/build-state.js +97 -0
  76. package/webpack/code.test.js +162 -0
  77. package/webpack/colors.js +15 -0
  78. package/webpack/config.base.js +147 -0
  79. package/webpack/config.dev.js +23 -0
  80. package/webpack/config.prod.js +32 -0
  81. package/webpack/content-watch-plugin.js +153 -0
  82. package/webpack/deflist-id-plugin.js +62 -0
  83. package/webpack/external-links-plugin.js +37 -0
  84. package/webpack/features.js +5 -0
  85. package/webpack/flair.json +1 -0
  86. package/webpack/generate-content-assets-plugin.js +308 -0
  87. package/webpack/generate-favicon-plugin.js +198 -0
  88. package/webpack/generate-fonts-plugin.js +69 -0
  89. package/webpack/generate-manifest-plugin.js +116 -0
  90. package/webpack/globals.js +74 -0
  91. package/webpack/heading-subtitle-plugin.js +80 -0
  92. package/webpack/json-schema.js +19 -0
  93. package/webpack/log.js +143 -0
  94. package/webpack/markdown-plugins.test.js +203 -0
  95. package/webpack/pagefind-plugin.js +379 -0
  96. package/webpack/pagefind-plugin.test.js +131 -0
  97. package/webpack/pdf-text.js +163 -0
  98. package/webpack/print-flair-plugin.js +22 -0
  99. package/webpack/reachability.js +273 -0
  100. package/webpack/reachability.test.js +80 -0
  101. package/webpack/serve.js +104 -0
  102. package/webpack/site-variables.js +53 -0
  103. package/webpack/site.schema.json +67 -0
  104. package/webpack/templates.js +128 -0
  105. package/webpack/text-to-id.js +8 -0
  106. package/webpack/toc-plugin.js +167 -0
  107. package/webpack/util.js +49 -0
  108. package/webpack/utils/code.js +439 -0
  109. package/webpack/utils/content-files.js +147 -0
  110. package/webpack/utils/define-plugin.js +20 -0
  111. package/webpack/utils/file-types.js +26 -0
  112. package/webpack/utils/front-matter.js +57 -0
  113. package/webpack/utils/jdi-runner/LiterateRunner.class +0 -0
  114. package/webpack/utils/jdi-runner/LiterateRunner.java +241 -0
  115. package/webpack/utils/literate-java.js +153 -0
  116. package/webpack/utils/markdown.js +244 -0
  117. package/webpack/utils/parse-hsl.js +8 -0
  118. package/webpack/utils/paths.js +58 -0
  119. package/webpack/utils/render.js +466 -0
  120. package/webpack/utils/shiki-highlighter.js +26 -0
  121. package/webpack/validate-internal-links-plugin.js +155 -0
  122. package/webpack/watch-reachability-state.js +273 -0
  123. package/webpack/watch-reachability-state.test.js +198 -0
  124. package/webpack/watch-reload-client.js +54 -0
  125. package/webpack/watch.js +166 -0
@@ -0,0 +1,244 @@
1
+ const MarkdownIt = require('markdown-it');
2
+ const { convertMarkdown: curlyQuote } = require('quote-quote');
3
+ const textToId = require('../text-to-id');
4
+ const { getHighlighter } = require('./shiki-highlighter');
5
+
6
+ function capitalize(str) {
7
+ if (str.length < 2) {
8
+ return str;
9
+ }
10
+
11
+ return str[0].toUpperCase() + str.slice(1);
12
+ }
13
+
14
+ function createMarkdown(siteVariables, options = {}) {
15
+ const { validatorOptions = {} } = options;
16
+ const markdown = new MarkdownIt({ html: true, typographer: true })
17
+ .use(require('../heading-subtitle-plugin'))
18
+ .use(require('markdown-it-anchor'), { tabIndex: false })
19
+ .use(require('markdown-it-footnote'))
20
+ .use(require('markdown-it-deflist'))
21
+ .use(require('../deflist-id-plugin'))
22
+ .use(require('../external-links-plugin'), siteVariables)
23
+ .use(require('../validate-internal-links-plugin'), validatorOptions)
24
+ .use(require('../apply-base-path-plugin'), siteVariables)
25
+ .use(require('../toc-plugin').tocPlugin)
26
+ .use(require('markdown-it-container'), 'details', {
27
+ marker: '<',
28
+ validate: function (params) {
29
+ return params.trim().match(/^details\s+(.*)$/);
30
+ },
31
+
32
+ render: function (tokens, idx) {
33
+ var m = tokens[idx].info.trim().match(/^details\s+(.*)$/);
34
+
35
+ if (tokens[idx].nesting === 1) {
36
+ return (
37
+ '<details><summary>' +
38
+ markdown.renderInline(m[1]) +
39
+ '</summary><div class="content">\n'
40
+ );
41
+ } else {
42
+ return '</div></details>\n';
43
+ }
44
+ },
45
+ })
46
+ .use(require('markdown-it-container'), 'section', {
47
+ marker: ':',
48
+ validate: function (params) {
49
+ return params.trim().match(/^section$/);
50
+ },
51
+ render: function (tokens, idx) {
52
+ if (tokens[idx].nesting === 1) {
53
+ return '<section>\n';
54
+ } else {
55
+ return '</section>\n';
56
+ }
57
+ },
58
+ });
59
+
60
+ const usedIds = new Map();
61
+ markdown.use(require('markdown-it-container'), 'alert', {
62
+ marker: '!',
63
+ validate: function (params) {
64
+ return params.trim().match(/^(note|warning)\s*"?(.+)?"?$/);
65
+ },
66
+ render: function (tokens, idx) {
67
+ const matches = tokens[idx].info
68
+ .trim()
69
+ .match(/^(note|warning)\s*"?(.+)?"?$/);
70
+
71
+ if (tokens[idx].nesting === 1) {
72
+ const classNames = ['alert'];
73
+ const type = matches && matches[1]?.trim();
74
+ if (type) {
75
+ classNames.push(type);
76
+ }
77
+
78
+ const title = matches && matches[2]?.trim();
79
+
80
+ let html = `<div class="${classNames.join(' ')}">`;
81
+ if (title) {
82
+ const baseId = textToId(title);
83
+ const count = (usedIds.get(baseId) ?? 0) + 1;
84
+ usedIds.set(baseId, count);
85
+ const titleId = count === 1 ? baseId : `${baseId}-${count}`;
86
+ const renderedTitle = markdown.utils.escapeHtml(curlyQuote(title));
87
+ html += `<p class="title" id="${titleId}">${renderedTitle}</p>\n`;
88
+ } else {
89
+ const defaultTitle = capitalize(type);
90
+ html += `<p class="title">${defaultTitle}</p>\n`;
91
+ }
92
+ html += '<div class="content">\n';
93
+ return html;
94
+ } else {
95
+ return '</div></div>\n';
96
+ }
97
+ },
98
+ });
99
+
100
+ markdown.use(require('markdown-it-container'), 'question', {
101
+ marker: '?',
102
+ validate: function (params) {
103
+ return params.trim().match(/^question\s+(.+)$/);
104
+ },
105
+ render: function (tokens, idx) {
106
+ const m = tokens[idx].info.trim().match(/^question\s+(.+)$/);
107
+ if (tokens[idx].nesting === 1) {
108
+ const question = markdown.renderInline(m[1]);
109
+ return (
110
+ '<div class="question">' +
111
+ '<p class="question-q"><span class="question-label">Q.</span><span>' +
112
+ question +
113
+ '</span></p>' +
114
+ '<div class="question-a">' +
115
+ '<p class="question-a-label">A.</p>' +
116
+ '<div class="question-a-body" data-pagefind-ignore>\n'
117
+ );
118
+ } else {
119
+ return '</div></div></div>\n';
120
+ }
121
+ },
122
+ });
123
+
124
+ /*
125
+ * Customize markdown-it-footnote renderer
126
+ */
127
+ markdown.renderer.rules.footnote_block_open = () =>
128
+ '<div class="footnotes"><p class="title">Footnotes</p><ol>';
129
+
130
+ markdown.renderer.rules.footnote_block_close = () => '</ol></div>';
131
+
132
+ // Change appearance of reference
133
+ const caption = markdown.renderer.rules.footnote_caption;
134
+ markdown.renderer.rules.footnote_caption = (...args) => {
135
+ const str = caption(...args);
136
+ return str.slice(1, str.length - 1);
137
+ };
138
+
139
+ const footnoteRef = markdown.renderer.rules.footnote_ref;
140
+ markdown.renderer.rules.footnote_ref = (...args) =>
141
+ footnoteRef(...args)
142
+ .replace('<sup class="footnote-ref">', '')
143
+ .replace('</sup>', '')
144
+ .replace('<a href="', '<a class="footnote-ref" href="');
145
+
146
+ const footnoteAnchor = markdown.renderer.rules.footnote_anchor;
147
+ markdown.renderer.rules.footnote_anchor = (...args) =>
148
+ footnoteAnchor(...args).replace('\u21a9\uFE0E', '\u2191');
149
+
150
+ /*
151
+ * Customize lists (add wrapper element)
152
+ */
153
+ const proxy = (tokens, idx, options, env, self) =>
154
+ self.renderToken(tokens, idx, options);
155
+
156
+ const itemOpen = markdown.renderer.rules.list_item_open || proxy;
157
+ markdown.renderer.rules.list_item_open = (
158
+ tokens,
159
+ idx,
160
+ options,
161
+ env,
162
+ self,
163
+ ) => {
164
+ return (
165
+ itemOpen(tokens, idx, options, env, self) +
166
+ '<div class="styled-list-item">'
167
+ );
168
+ };
169
+
170
+ const itemClose = markdown.renderer.rules.list_item_close || proxy;
171
+ markdown.renderer.rules.list_item_close = (...args) => {
172
+ return '</div>' + itemClose(...args);
173
+ };
174
+
175
+ const bulletListOpen = markdown.renderer.rules.bullet_list_open || proxy;
176
+ markdown.renderer.rules.bullet_list_open = (
177
+ tokens,
178
+ idx,
179
+ options,
180
+ env,
181
+ self,
182
+ ) => {
183
+ tokens[idx].attrJoin('class', 'styled-list');
184
+ return bulletListOpen(tokens, idx, options, env, self);
185
+ };
186
+
187
+ const orderedListOpen = markdown.renderer.rules.ordered_list_open || proxy;
188
+ markdown.renderer.rules.ordered_list_open = (
189
+ tokens,
190
+ idx,
191
+ options,
192
+ env,
193
+ self,
194
+ ) => {
195
+ tokens[idx].attrJoin('class', 'styled-list');
196
+ return orderedListOpen(tokens, idx, options, env, self);
197
+ };
198
+
199
+ // Convert <!--- comments containing fences into hidden_fence tokens
200
+ markdown.core.ruler.push('hidden_fence', state => {
201
+ for (let i = state.tokens.length - 1; i >= 0; i--) {
202
+ const token = state.tokens[i];
203
+ if (token.type !== 'html_block') {
204
+ continue;
205
+ }
206
+
207
+ const src = token.content.trim();
208
+ if (!src.startsWith('<!---') || !src.endsWith('-->')) {
209
+ continue;
210
+ }
211
+
212
+ const inner = src.slice(5, -3).trim();
213
+ const fenceMatch = inner.match(/^```\w*\n?([\s\S]*?)```$/m);
214
+ if (!fenceMatch) {
215
+ continue;
216
+ }
217
+
218
+ token.type = 'hidden_fence';
219
+ token.tag = 'code';
220
+ token.content = fenceMatch[1];
221
+ }
222
+ });
223
+
224
+ markdown.renderer.rules.hidden_fence = () => '';
225
+
226
+ markdown.renderer.rules.fence = (tokens, idx) => {
227
+ const token = tokens[idx];
228
+ const lang = token.info.trim().split(/\s+/)[0] || 'text';
229
+ const code = token.content;
230
+ const highlighter = getHighlighter();
231
+ const useLang = highlighter.getLoadedLanguages().includes(lang)
232
+ ? lang
233
+ : 'text';
234
+ return highlighter.codeToHtml(code, {
235
+ lang: useLang,
236
+ themes: { light: 'github-light', dark: 'github-dark' },
237
+ defaultColor: false,
238
+ });
239
+ };
240
+
241
+ return markdown;
242
+ }
243
+
244
+ module.exports = { createMarkdown };
@@ -0,0 +1,8 @@
1
+ function parseHsl(hslColor) {
2
+ const [, hue, saturation, lightness] = hslColor.match(
3
+ /^hsl\((\d+)(?:deg)?\s+(\d+)%\s+(\d+)%\)$/,
4
+ );
5
+ return { hue, saturation, lightness };
6
+ }
7
+
8
+ module.exports = { parseHsl };
@@ -0,0 +1,58 @@
1
+ const path = require('path');
2
+
3
+ function getPackageDir() {
4
+ return path.resolve(__dirname, '..', '..');
5
+ }
6
+
7
+ function getProjectDir() {
8
+ return process.cwd();
9
+ }
10
+
11
+ function getContentDir() {
12
+ return path.resolve(getProjectDir(), 'content');
13
+ }
14
+
15
+ function getDistDir() {
16
+ return path.resolve(getProjectDir(), 'dist');
17
+ }
18
+
19
+ function getPublicDir() {
20
+ return path.resolve(getProjectDir(), 'public');
21
+ }
22
+
23
+ function getConfigDir() {
24
+ return path.resolve(getProjectDir(), 'config');
25
+ }
26
+
27
+ function createApplyBasePath(siteVariables) {
28
+ return function applyBasePath(subPath) {
29
+ if (!subPath.startsWith('/')) {
30
+ throw new Error('invalid internal path, must start with "/": ' + subPath);
31
+ }
32
+
33
+ let path = siteVariables.basePath || '/';
34
+ if (path.endsWith('/')) {
35
+ path = path.slice(0, -1);
36
+ }
37
+ return path + subPath;
38
+ };
39
+ }
40
+
41
+ function normalizeOutputPath(outputPath) {
42
+ const normalized = path.posix.normalize(outputPath);
43
+ if (normalized === '.' || normalized === '') {
44
+ return '/';
45
+ }
46
+ return normalized.startsWith('/') ? normalized : `/${normalized}`;
47
+ }
48
+
49
+ module.exports = {
50
+ createApplyBasePath,
51
+ getConfigDir,
52
+ getContentDir,
53
+ getDistDir,
54
+ getPackageDir,
55
+ getProjectDir,
56
+ getPublicDir,
57
+ normalizeOutputPath,
58
+ };