Repository: danvk/literate-ts
Pull request #17 (2020-07-04 20:01:37)

Support //-style directives in markdown
Useful for hiding code samples for prepending


Patch:
diff --git a/README.md b/README.md
index 32d6fbf..f05bd6c 100644
--- a/README.md
+++ b/README.md
@@ -135,6 +135,10 @@ starting with `verifier:` immediately before the sample. For example:
     const student: Student = { name: 'Bobby Droppers', age: 12 };
     ```
 
+You may also use `// #id` or `// verifier:directive` as an alternative form.
+This is primarily useful if you want to prepend a code sample that's hidden inside an
+HTML comment.
+
 See below for a complete list of directives.
 
 ### Asciidoc
diff --git a/package.json b/package.json
index ca5ac0b..3f2269a 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "literate-ts",
-  "version": "1.0.0",
+  "version": "1.1.0",
   "description": "Code samples that scale",
   "main": "dist/index.js",
   "repository": "https://github.com/danvk/literate-ts.git",
diff --git a/src/markdown.ts b/src/markdown.ts
index 53af0c3..94bbfea 100644
--- a/src/markdown.ts
+++ b/src/markdown.ts
@@ -3,6 +3,8 @@ import {Processor} from './code-sample';
 
 const EXTRACT_ID = /<!-- #([^ ]+) -->/;
 const EXTRACT_DIRECTIVE = /<!-- verifier:(.*) -->/;
+const ALT_EXTRACT_ID = /^\/\/ #([^ ]+)$/;
+const ALT_EXTRACT_DIRECTIVE = /^\/\/ verifier:(.*)$/;
 const TOP_HEADER = /^#{1,3} (.*)$/;
 
 export function extractMarkdownSamples(text: string, p: Processor) {
@@ -10,9 +12,10 @@ export function extractMarkdownSamples(text: string, p: Processor) {
 
   for (let i = 0; i < lines.length; i++) {
     const line = lines[i];
-    const id = matchAndExtract(EXTRACT_ID, line);
+    const id = matchAndExtract(EXTRACT_ID, line) || matchAndExtract(ALT_EXTRACT_ID, line);
     const header = matchAndExtract(TOP_HEADER, line);
-    const directive = matchAndExtract(EXTRACT_DIRECTIVE, line);
+    const directive =
+      matchAndExtract(EXTRACT_DIRECTIVE, line) || matchAndExtract(ALT_EXTRACT_DIRECTIVE, line);
 
     if (id) {
       p.setNextId(id);


Test patch:
diff --git a/src/test/__snapshots__/asciidoc.test.ts.snap b/src/test/__snapshots__/asciidoc.test.ts.snap
index 36cda70..9bb7ee2 100644
--- a/src/test/__snapshots__/asciidoc.test.ts.snap
+++ b/src/test/__snapshots__/asciidoc.test.ts.snap
@@ -1,5 +1,48 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
+exports[`extractSamples snapshot: commented-sample 1`] = `
+Array [
+  Object {
+    "checkJS": false,
+    "content": "function somethingDangerous() {}",
+    "id": "commented-sample-6",
+    "isTSX": false,
+    "language": "ts",
+    "nodeModules": Array [],
+    "prefixes": Array [],
+    "sectionHeader": null,
+    "sectionId": null,
+    "sourceFile": "commented-sample.asciidoc",
+    "tsOptions": Object {},
+  },
+  Object {
+    "checkJS": false,
+    "content": "let val = null;  // Type is any
+try {
+  somethingDangerous();
+  val = 12;
+  val  // Type is number
+} catch (e) {
+  console.warn('alas!');
+}
+val  // Type is number | null",
+    "id": "commented-sample-12",
+    "isTSX": false,
+    "language": "ts",
+    "nodeModules": Array [],
+    "prefixes": Array [
+      Object {
+        "id": "commented-sample-6",
+      },
+    ],
+    "sectionHeader": null,
+    "sectionId": null,
+    "sourceFile": "commented-sample.asciidoc",
+    "tsOptions": Object {},
+  },
+]
+`;
+
 exports[`extractSamples snapshot: doc1 1`] = `
 Array [
   Object {
diff --git a/src/test/__snapshots__/markdown.test.ts.snap b/src/test/__snapshots__/markdown.test.ts.snap
index fb5b734..f4eb90a 100644
--- a/src/test/__snapshots__/markdown.test.ts.snap
+++ b/src/test/__snapshots__/markdown.test.ts.snap
@@ -1,5 +1,48 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
+exports[`markdown should match snapshots: commented-sample 1`] = `
+Array [
+  Object {
+    "checkJS": false,
+    "content": "function somethingDangerous() {}",
+    "id": "commented-sample-5",
+    "isTSX": false,
+    "language": "ts",
+    "nodeModules": Array [],
+    "prefixes": Array [],
+    "sectionHeader": null,
+    "sectionId": null,
+    "sourceFile": "commented-sample.md",
+    "tsOptions": Object {},
+  },
+  Object {
+    "checkJS": false,
+    "content": "let val = null;  // Type is any
+try {
+  somethingDangerous();
+  val = 12;
+  val  // Type is number
+} catch (e) {
+  console.warn('alas!');
+}
+val  // Type is number | null",
+    "id": "commented-sample-10",
+    "isTSX": false,
+    "language": "ts",
+    "nodeModules": Array [],
+    "prefixes": Array [
+      Object {
+        "id": "commented-sample-5",
+      },
+    ],
+    "sectionHeader": null,
+    "sectionId": null,
+    "sourceFile": "commented-sample.md",
+    "tsOptions": Object {},
+  },
+]
+`;
+
 exports[`markdown should match snapshots: doc1 1`] = `
 Array [
   Object {
diff --git a/src/test/asciidoc.test.ts b/src/test/asciidoc.test.ts
index e523632..065d46b 100644
--- a/src/test/asciidoc.test.ts
+++ b/src/test/asciidoc.test.ts
@@ -1,4 +1,6 @@
 import fs from 'fs';
+import glob from 'glob';
+import path from 'path';
 
 import {dedent} from '../utils';
 import {extractSamples} from '../code-sample';
@@ -77,19 +79,11 @@ const a: AB = 'a';
 
 describe('extractSamples', () => {
   test('snapshot', () => {
-    const dir = './src/test/inputs';
-
-    // TODO(danvk): use a glob here
-    const inputs = ['doc1', 'noid', 'prepend', 'prepend-multiple', 'skip', 'multilinetype'];
-
-    for (const input of inputs) {
-      expect(
-        extractSamples(
-          fs.readFileSync(`${dir}/${input}.asciidoc`, 'utf8'),
-          input,
-          `${input}.asciidoc`,
-        ),
-      ).toMatchSnapshot(input);
+    const inputFiles = glob.sync('./src/test/inputs/*.asciidoc');
+
+    for (const inputFile of inputFiles) {
+      const {base, name} = path.parse(inputFile);
+      expect(extractSamples(fs.readFileSync(inputFile, 'utf8'), name, base)).toMatchSnapshot(name);
     }
   });
 
diff --git a/src/test/inputs/commented-sample.asciidoc b/src/test/inputs/commented-sample.asciidoc
new file mode 100644
index 0000000..4ff3a9e
--- /dev/null
+++ b/src/test/inputs/commented-sample.asciidoc
@@ -0,0 +1,22 @@
+A final case that triggers this "evolving any" behavior is if a variable is initially `null`. This often comes up when you set a value in a `try`/`catch` block:
+
+////
+// verifier:prepend-to-following
+[source,ts]
+----
+function somethingDangerous() {}
+----
+////
+
+[source,ts]
+----
+let val = null;  // Type is any
+try {
+  somethingDangerous();
+  val = 12;
+  val  // Type is number
+} catch (e) {
+  console.warn('alas!');
+}
+val  // Type is number | null
+----
diff --git a/src/test/inputs/commented-sample.md b/src/test/inputs/commented-sample.md
new file mode 100644
index 0000000..9772ba9
--- /dev/null
+++ b/src/test/inputs/commented-sample.md
@@ -0,0 +1,20 @@
+A final case that triggers this "evolving any" behavior is if a variable is initially `null`. This often comes up when you set a value in a `try`/`catch` block:
+
+<!--
+// verifier:prepend-to-following
+```ts
+function somethingDangerous() {}
+```
+-->
+
+```ts
+let val = null;  // Type is any
+try {
+  somethingDangerous();
+  val = 12;
+  val  // Type is number
+} catch (e) {
+  console.warn('alas!');
+}
+val  // Type is number | null
+```
diff --git a/src/test/markdown.test.ts b/src/test/markdown.test.ts
index 8fce2e9..df2f7ec 100644
--- a/src/test/markdown.test.ts
+++ b/src/test/markdown.test.ts
@@ -1,18 +1,16 @@
 import fs from 'fs';
+import glob from 'glob';
+import path from 'path';
 
 import {extractSamples} from '../code-sample';
 
 describe('markdown', () => {
   it('should match snapshots', () => {
-    const dir = './src/test/inputs';
+    const inputFiles = glob.sync('./src/test/inputs/*.md');
 
-    // TODO(danvk): use a glob here
-    const inputs = ['doc1', 'noid', 'prepend', 'prepend-multiple', 'skip', 'multilinetype'];
-
-    for (const input of inputs) {
-      expect(
-        extractSamples(fs.readFileSync(`${dir}/${input}.md`, 'utf8'), input, `${input}.md`),
-      ).toMatchSnapshot(input);
+    for (const inputFile of inputFiles) {
+      const {base, name} = path.parse(inputFile);
+      expect(extractSamples(fs.readFileSync(inputFile, 'utf8'), name, base)).toMatchSnapshot(name);
     }
   });
 });