├── .babelrc ├── .eslintrc ├── .gitignore ├── .travis.yml ├── README.md ├── docs ├── MarkdownNode.html ├── fonts │ ├── OpenSans-Bold-webfont.eot │ ├── OpenSans-Bold-webfont.svg │ ├── OpenSans-Bold-webfont.woff │ ├── OpenSans-BoldItalic-webfont.eot │ ├── OpenSans-BoldItalic-webfont.svg │ ├── OpenSans-BoldItalic-webfont.woff │ ├── OpenSans-Italic-webfont.eot │ ├── OpenSans-Italic-webfont.svg │ ├── OpenSans-Italic-webfont.woff │ ├── OpenSans-Light-webfont.eot │ ├── OpenSans-Light-webfont.svg │ ├── OpenSans-Light-webfont.woff │ ├── OpenSans-LightItalic-webfont.eot │ ├── OpenSans-LightItalic-webfont.svg │ ├── OpenSans-LightItalic-webfont.woff │ ├── OpenSans-Regular-webfont.eot │ ├── OpenSans-Regular-webfont.svg │ ├── OpenSans-Regular-webfont.woff │ ├── OpenSans-Semibold-webfont.eot │ ├── OpenSans-Semibold-webfont.svg │ ├── OpenSans-Semibold-webfont.ttf │ ├── OpenSans-Semibold-webfont.woff │ ├── OpenSans-SemiboldItalic-webfont.eot │ ├── OpenSans-SemiboldItalic-webfont.svg │ ├── OpenSans-SemiboldItalic-webfont.ttf │ └── OpenSans-SemiboldItalic-webfont.woff ├── index.html ├── markdown.js.html ├── scripts │ ├── linenumber.js │ └── prettify │ │ ├── Apache-License-2.0.txt │ │ ├── lang-css.js │ │ └── prettify.js └── styles │ ├── jsdoc-default.css │ ├── prettify-jsdoc.css │ └── prettify-tomorrow.css ├── package.json ├── src ├── __test__ │ ├── error.test.js │ ├── get.test.js │ ├── getAll.test.js │ ├── heading.test.js │ ├── index.test.js │ ├── paragraph.test.js │ ├── set.test.js │ ├── testHelper.js │ ├── type.test.js │ └── value.test.js ├── constants.js ├── error.js ├── index.js ├── markdown.js └── query │ ├── __test__ │ ├── query.test.js │ └── util.test.js │ ├── index.js │ └── util.js └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015"] 3 | } 4 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "es6": true, 4 | "node": true, 5 | "jest": true 6 | }, 7 | "extends": ["eslint:recommended"], 8 | "plugins": ["prettier", "import", "fp", "unicorn"], 9 | "rules": { 10 | "no-console": "off", 11 | "unicorn/explicit-length-check": "error", 12 | "unicorn/custom-error-definition": "error", 13 | "unicorn/prefer-type-error": "error", 14 | "unicorn/no-array-instanceof": "error", 15 | "fp/no-get-set": "error", 16 | "fp/no-mutating-assign": "error", 17 | "no-else-return": "error", 18 | "no-inner-declarations": "error", 19 | "no-unneeded-ternary": "error", 20 | "no-useless-return": "error", 21 | "no-var": "error", 22 | "no-new": "error", 23 | "no-undef-init": "error", 24 | "no-self-compare": "error", 25 | "no-throw-literal": "error", 26 | "no-useless-concat": "error", 27 | "no-use-before-define": "error", 28 | "no-unused-expressions": "error", 29 | "no-duplicate-imports": "error", 30 | "eqeqeq": "error", 31 | "complexity": "error", 32 | "block-scoped-var": "error", 33 | "dot-notation": "error", 34 | "one-var": ["error", "never"], 35 | "prefer-arrow-callback": "error", 36 | "prefer-const": "error", 37 | "prettier/prettier": "error", 38 | "strict": "error", 39 | "symbol-description": "error", 40 | "max-depth": "error", 41 | "max-lines": "error", 42 | "max-nested-callbacks": "error", 43 | "max-statements": "error" 44 | }, 45 | "parserOptions": { 46 | "ecmaFeatures": { 47 | "jsx": true 48 | }, 49 | "ecmaVersion": 6, 50 | "sourceType": "module" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | node_modules 3 | .DS_Store 4 | coverage 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "8" 4 | script: 5 | - yarn lint 6 | - yarn test 7 | cache: 8 | directories: 9 | - node_modules 10 | after_script: "cat ./coverage/lcov.info | ./node_modules/.bin/coveralls" -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mark-dom 2 | 3 | [![Build Status](https://travis-ci.org/Flaque/mark-dom.svg?branch=master)](https://travis-ci.org/Flaque/mark-dom) 4 | [![Coverage Status](https://coveralls.io/repos/github/Flaque/mark-dom/badge.svg?branch=master)](https://coveralls.io/github/Flaque/mark-dom?branch=master) 5 | 6 | Mark-dom is basically jQuery but for markdown. 7 | 8 | If you've ever wanted to write a script that only edits a single part of a markdown doc and leaves the rest alone, then hopefully this brings you joy. 9 | 10 | [Docs Here.](https://flaque.github.io/mark-dom/MarkdownNode.html) 11 | 12 | ## Install 13 | 14 | ``` 15 | $ npm install mark-dom 16 | ``` 17 | 18 | ## Example 19 | 20 | ### Our Example Markdown 21 | ``` markdown 22 | 23 | # Hello there 24 | I am some markdown 25 | 26 | ## Dogs are cool 27 | They bring you friendly joy. 28 | 29 | ## World peace is cool 30 | Let's bake some cakes and be nice to each other 31 | ``` 32 | 33 | ### Get a header value 34 | ``` js 35 | import mrk = require("mark-dom"); 36 | 37 | // Returns "World peace is cool" 38 | mrk(thatMarkdownStr) 39 | .heading("## World peace *") 40 | .value(); 41 | ``` 42 | 43 | ### Change a header 44 | ``` js 45 | import mrk = require("mark-dom"); 46 | 47 | // Return a new markdown string where the first header 48 | // is "Stuff that's cool" 49 | mrk(thatMarkdownStr) 50 | .heading() // gets the first heading! 51 | .set("Stuff that's cool"); 52 | .getAll(); 53 | ``` 54 | 55 | ### Change an entire paragraph 56 | ``` js 57 | import mrk = require("mark-dom"); 58 | 59 | // Change the "dogs" header and return a new markdown string 60 | mrk(thatMarkdownStr) 61 | .heading("## * ") // Get the first sub header 62 | .paragraph() 63 | .set("They make you smile.") 64 | .getAll(); 65 | ``` 66 | 67 | ## Status 68 | Mark-dom is really just an experiment at the moment and I haven't really fleshed out all of the API that I want yet. Things might change, at the time that I'm writing this, I don't think it even works. 69 | 70 | ### TODO list 71 | * ~Glob syntax `*`~ 72 | * Find tables 73 | * Find code 74 | * Find lists 75 | * Putting a 2d array in `set()` will create a table 76 | * Putting a 1d array in `set()` will create a list 77 | 78 | ## How's it work? 79 | Mark-dom uses [remark](https://github.com/wooorm/remark/tree/master/packages/remark) and it's ecosystem to parse the markdown into an Abstract Syntax Tree (AST), then it lets you navigate and edit the tree with an API and eventually construct a new markdown document by compiling the tree down to a string. 80 | 81 | ## What's the use case? 82 | * Auto-generating README's 83 | * Forcing standards/style-guides to docs 84 | * ??? 85 | * Profit! 86 | -------------------------------------------------------------------------------- /docs/MarkdownNode.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | MarkdownNode - Documentation 7 | 8 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 23 | 24 | 25 | 26 | 29 | 30 |
31 | 32 |

MarkdownNode

33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 |
41 | 42 |
43 | 44 |

45 | MarkdownNode 46 |

47 | 48 |
A MarkdownNode is an object describing a node in the 49 | Abstract Syntax Tree (AST) of the markdown.
50 | 51 | 52 |
53 | 54 |
55 |
56 | 57 | 58 |
59 | 60 | 61 |

Constructor

62 | 63 | 64 |

new MarkdownNode(src, optionsopt)

65 | 66 | 67 | 68 | 69 | 70 |
71 | A markdown node takes either an Abstract Syntax Tree (AST) 72 | or a markdown string. 73 |
74 | 75 | 76 | 77 | 78 | 79 |
80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 |
Source:
107 |
110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 |
118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 |
Parameters:
128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 168 | 169 | 170 | 177 | 178 | 179 | 180 | 181 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 202 | 203 | 204 | 213 | 214 | 215 | 216 | 217 | 221 | 222 | 223 | 224 | 225 |
NameTypeAttributesDescription
src 158 | 159 | 160 | ast 161 | | 162 | 163 | string 164 | 165 | 166 | 167 | 171 | 172 | 173 | 174 | 175 | 176 | 182 | The markdown string that we'll parse into an AST. 183 | 184 |
options 195 | 196 | 197 | JSON 198 | 199 | 200 | 201 | 205 | 206 | <optional>
207 | 208 | 209 | 210 | 211 | 212 |
218 | Options to be passed into MarkdownNode 219 | 220 |
226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 |
243 |
Example
244 | 245 |
import mrk = require("mark-dom");
 246 | mrk("# Hello").get(); // Will return "# Hello"
247 | 248 |
249 | 250 |
251 | 252 |
253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 |

Methods

268 | 269 | 270 | 271 |
272 | 273 | 274 | 275 |

get() → {String}

276 | 277 | 278 | 279 | 280 | 281 |
282 | Returns the markdown string version of the node you're currently on. 283 |
284 | 285 | 286 | 287 | 288 | 289 |
290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 |
Source:
317 |
320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 |
328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 |
350 |
Returns:
351 | 352 | 353 | 354 |
355 |
356 | Type: 357 |
358 |
359 | 360 | String 361 | 362 | 363 |
364 |
365 | 366 | 367 |
368 | The String version of the CURRENT node we're on. 369 |
370 | 371 | 372 |
373 | 374 | 375 | 376 |
377 |
Example
378 | 379 |
// Returns "## Subheader"
 380 | mrk(`
 381 | # Hello
 382 | ## Subheader
 383 | `).heading("## *").get();
384 | 385 |
386 | 387 |
388 | 389 | 390 |
391 | 392 | 393 | 394 |

getAll() → {String}

395 | 396 | 397 | 398 | 399 | 400 |
401 | Returns the markdown string version of the entire AST of this piece of 402 | markdown. 403 |
404 | 405 | 406 | 407 | 408 | 409 |
410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 |
Source:
437 |
440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 |
448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 |
470 |
Returns:
471 | 472 | 473 | 474 |
475 |
476 | Type: 477 |
478 |
479 | 480 | String 481 | 482 | 483 |
484 |
485 | 486 | 487 |
488 | The String version of the ENTIRE compiled Markdown AST. 489 |
490 | 491 | 492 |
493 | 494 | 495 | 496 |
497 | 498 | 499 |
500 | 501 | 502 | 503 |

heading(searchWordopt) → {MarkdownNode}

504 | 505 | 506 | 507 | 508 | 509 |
510 | Gets a new MarkdownNode representing the first heading it finds. 511 |
512 | 513 | 514 | 515 | 516 | 517 |
518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 |
Source:
545 |
548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 |
556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | 565 |
Parameters:
566 | 567 | 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 603 | 604 | 605 | 614 | 615 | 616 | 617 | 618 | 622 | 623 | 624 | 625 | 626 |
NameTypeAttributesDescription
searchWord 596 | 597 | 598 | String 599 | 600 | 601 | 602 | 606 | 607 | <optional>
608 | 609 | 610 | 611 | 612 | 613 |
619 | A string to search for in the heading. Can use wildcard * syntax. 620 | 621 |
627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 |
642 |
Returns:
643 | 644 | 645 | 646 |
647 |
648 | Type: 649 |
650 |
651 | 652 | MarkdownNode 653 | 654 | 655 |
656 |
657 | 658 | 659 |
660 | A new child node at the next heading. 661 |
662 | 663 | 664 |
665 | 666 | 667 | 668 |
669 |
Examples
670 | 671 |
// Returns a MarkdownNode at the heading.
 672 | mrk("# Hello").heading("H*");
673 | 674 |
// Returns a MarkdownNode representing "# First"
 675 | mrk(`
 676 | # First 
 677 | some text
 678 | 
 679 | # Second
 680 | other text
 681 | `).heading();
682 | 683 |
684 | 685 |
686 | 687 | 688 |
689 | 690 | 691 | 692 |

paragraph(searchWordopt) → {MarkdownNode}

693 | 694 | 695 | 696 | 697 | 698 |
699 | Gets a new MarkdownNode representing the first paragraph it finds. 700 |
701 | 702 | 703 | 704 | 705 | 706 |
707 | 708 | 709 | 710 | 711 | 712 | 713 | 714 | 715 | 716 | 717 | 718 | 719 | 720 | 721 | 722 | 723 | 724 | 725 | 726 | 727 | 728 | 729 | 730 | 731 | 732 | 733 |
Source:
734 |
737 | 738 | 739 | 740 | 741 | 742 | 743 | 744 |
745 | 746 | 747 | 748 | 749 | 750 | 751 | 752 | 753 | 754 |
Parameters:
755 | 756 | 757 | 758 | 759 | 760 | 761 | 762 | 763 | 764 | 765 | 766 | 767 | 768 | 769 | 770 | 771 | 772 | 773 | 774 | 775 | 776 | 777 | 778 | 779 | 780 | 781 | 782 | 783 | 784 | 792 | 793 | 794 | 803 | 804 | 805 | 806 | 807 | 811 | 812 | 813 | 814 | 815 |
NameTypeAttributesDescription
searchWord 785 | 786 | 787 | String 788 | 789 | 790 | 791 | 795 | 796 | <optional>
797 | 798 | 799 | 800 | 801 | 802 |
808 | A string to search for in the paragraph. Can use wildcard * syntax. 809 | 810 |
816 | 817 | 818 | 819 | 820 | 821 | 822 | 823 | 824 | 825 | 826 | 827 | 828 | 829 | 830 |
831 |
Returns:
832 | 833 | 834 | 835 |
836 |
837 | Type: 838 |
839 |
840 | 841 | MarkdownNode 842 | 843 | 844 |
845 |
846 | 847 | 848 | 849 |
850 | 851 | 852 | 853 |
854 |
Examples
855 | 856 |
// Returns a MarkdownNode at the paragraph.
 857 | mrk("Hello").paragraph("H*");
858 | 859 |
// Returns a MarkdownNode representing "First Paragraph"
 860 | mrk(`
 861 | # First 
 862 | First Paragraph
 863 | 
 864 | # Second
 865 | Second Paragraph
 866 | `).paragraph();
867 | 868 |
869 | 870 |
871 | 872 | 873 |
874 | 875 | 876 | 877 | 878 | 879 | 880 | 881 | 882 | 883 |
884 | Gets a new MarkdownNode representing an aribtary AST type. 885 |
886 | 887 | 888 | 889 | 890 | 891 |
892 | 893 | 894 | 895 | 896 | 897 | 898 | 899 | 900 | 901 | 902 | 903 | 904 | 905 | 906 | 907 | 908 | 909 | 910 | 911 | 912 | 913 | 914 | 915 | 916 | 917 | 918 |
Source:
919 |
922 | 923 | 924 | 925 | 926 | 927 | 928 | 929 |
930 | 931 | 932 | 933 | 934 | 935 | 936 | 937 | 938 | 939 |
Parameters:
940 | 941 | 942 | 943 | 944 | 945 | 946 | 947 | 948 | 949 | 950 | 951 | 952 | 953 | 954 | 955 | 956 | 957 | 958 | 959 | 960 | 961 | 962 | 963 | 964 | 965 | 966 | 967 | 968 | 969 | 977 | 978 | 979 | 986 | 987 | 988 | 989 | 990 | 994 | 995 | 996 | 997 | 998 | 999 | 1000 | 1001 | 1002 | 1003 | 1011 | 1012 | 1013 | 1022 | 1023 | 1024 | 1025 | 1026 | 1030 | 1031 | 1032 | 1033 | 1034 |
NameTypeAttributesDescription
type 970 | 971 | 972 | String 973 | 974 | 975 | 976 | 980 | 981 | 982 | 983 | 984 | 985 | 991 | 992 | 993 |
searchWord 1004 | 1005 | 1006 | String 1007 | 1008 | 1009 | 1010 | 1014 | 1015 | <optional>
1016 | 1017 | 1018 | 1019 | 1020 | 1021 |
1027 | A string to search for in the node. Can use wildcard * syntax. 1028 | 1029 |
1035 | 1036 | 1037 | 1038 | 1039 | 1040 | 1041 | 1042 | 1043 | 1044 | 1045 | 1046 | 1047 | 1048 | 1049 | 1050 | 1051 |
1052 |
Example
1053 | 1054 |
// Returns "# Hello"
1055 | mrk().set("# Hello").search("# H*").getAll();
1056 | 1057 |
1058 | 1059 |
1060 | 1061 | 1062 |
1063 | 1064 | 1065 | 1066 |

set(str) → {MarkdownNode}

1067 | 1068 | 1069 | 1070 | 1071 | 1072 |
1073 | Sets the current node's value to the str input 1074 |
1075 | 1076 | 1077 | 1078 | 1079 | 1080 |
1081 | 1082 | 1083 | 1084 | 1085 | 1086 | 1087 | 1088 | 1089 | 1090 | 1091 | 1092 | 1093 | 1094 | 1095 | 1096 | 1097 | 1098 | 1099 | 1100 | 1101 | 1102 | 1103 | 1104 | 1105 | 1106 | 1107 |
Source:
1108 |
1111 | 1112 | 1113 | 1114 | 1115 | 1116 | 1117 | 1118 |
1119 | 1120 | 1121 | 1122 | 1123 | 1124 | 1125 | 1126 | 1127 | 1128 |
Parameters:
1129 | 1130 | 1131 | 1132 | 1133 | 1134 | 1135 | 1136 | 1137 | 1138 | 1139 | 1140 | 1141 | 1142 | 1143 | 1144 | 1145 | 1146 | 1147 | 1148 | 1149 | 1150 | 1151 | 1152 | 1153 | 1154 | 1155 | 1156 | 1164 | 1165 | 1166 | 1167 | 1168 | 1169 | 1173 | 1174 | 1175 | 1176 | 1177 |
NameTypeDescription
str 1157 | 1158 | 1159 | String 1160 | 1161 | 1162 | 1163 | 1170 | 1171 | 1172 |
1178 | 1179 | 1180 | 1181 | 1182 | 1183 | 1184 | 1185 | 1186 | 1187 | 1188 | 1189 | 1190 | 1191 | 1192 |
1193 |
Returns:
1194 | 1195 | 1196 | 1197 |
1198 |
1199 | Type: 1200 |
1201 |
1202 | 1203 | MarkdownNode 1204 | 1205 | 1206 |
1207 |
1208 | 1209 | 1210 | 1211 |
1212 | 1213 | 1214 | 1215 |
1216 | 1217 | 1218 |
1219 | 1220 | 1221 | 1222 |

setTable(array) → {MarkdownNode}

1223 | 1224 | 1225 | 1226 | 1227 | 1228 |
1229 | Create a markdown table from an array. 1230 |
1231 | 1232 | 1233 | 1234 | 1235 | 1236 |
1237 | 1238 | 1239 | 1240 | 1241 | 1242 | 1243 | 1244 | 1245 | 1246 | 1247 | 1248 | 1249 | 1250 | 1251 | 1252 | 1253 | 1254 | 1255 | 1256 | 1257 | 1258 | 1259 | 1260 | 1261 | 1262 | 1263 |
Source:
1264 |
1267 | 1268 | 1269 | 1270 | 1271 | 1272 | 1273 | 1274 |
1275 | 1276 | 1277 | 1278 | 1279 | 1280 | 1281 | 1282 | 1283 | 1284 |
Parameters:
1285 | 1286 | 1287 | 1288 | 1289 | 1290 | 1291 | 1292 | 1293 | 1294 | 1295 | 1296 | 1297 | 1298 | 1299 | 1300 | 1301 | 1302 | 1303 | 1304 | 1305 | 1306 | 1307 | 1308 | 1309 | 1310 | 1311 | 1312 | 1320 | 1321 | 1322 | 1323 | 1324 | 1325 | 1329 | 1330 | 1331 | 1332 | 1333 |
NameTypeDescription
array 1313 | 1314 | 1315 | Array 1316 | 1317 | 1318 | 1319 | 1326 | 1327 | 1328 |
1334 | 1335 | 1336 | 1337 | 1338 | 1339 | 1340 | 1341 | 1342 | 1343 | 1344 | 1345 | 1346 | 1347 | 1348 |
1349 |
Returns:
1350 | 1351 | 1352 | 1353 |
1354 |
1355 | Type: 1356 |
1357 |
1358 | 1359 | MarkdownNode 1360 | 1361 | 1362 |
1363 |
1364 | 1365 | 1366 | 1367 |
1368 | 1369 | 1370 | 1371 |
1372 | 1373 | 1374 |
1375 | 1376 | 1377 | 1378 |

table(searchWordopt) → {MarkdownNode}

1379 | 1380 | 1381 | 1382 | 1383 | 1384 |
1385 | Gets a new MarkdownNode representing the first paragraph it finds 1386 |
1387 | 1388 | 1389 | 1390 | 1391 | 1392 |
1393 | 1394 | 1395 | 1396 | 1397 | 1398 | 1399 | 1400 | 1401 | 1402 | 1403 | 1404 | 1405 | 1406 | 1407 | 1408 | 1409 | 1410 | 1411 | 1412 | 1413 | 1414 | 1415 | 1416 | 1417 | 1418 | 1419 |
Source:
1420 |
1423 | 1424 | 1425 | 1426 | 1427 | 1428 | 1429 | 1430 |
1431 | 1432 | 1433 | 1434 | 1435 | 1436 | 1437 | 1438 | 1439 | 1440 |
Parameters:
1441 | 1442 | 1443 | 1444 | 1445 | 1446 | 1447 | 1448 | 1449 | 1450 | 1451 | 1452 | 1453 | 1454 | 1455 | 1456 | 1457 | 1458 | 1459 | 1460 | 1461 | 1462 | 1463 | 1464 | 1465 | 1466 | 1467 | 1468 | 1469 | 1470 | 1478 | 1479 | 1480 | 1489 | 1490 | 1491 | 1492 | 1493 | 1497 | 1498 | 1499 | 1500 | 1501 |
NameTypeAttributesDescription
searchWord 1471 | 1472 | 1473 | String 1474 | 1475 | 1476 | 1477 | 1481 | 1482 | <optional>
1483 | 1484 | 1485 | 1486 | 1487 | 1488 |
1494 | A string to search for somewhere in the table. Can use wildcard * syntax. 1495 | 1496 |
1502 | 1503 | 1504 | 1505 | 1506 | 1507 | 1508 | 1509 | 1510 | 1511 | 1512 | 1513 | 1514 | 1515 | 1516 |
1517 |
Returns:
1518 | 1519 | 1520 | 1521 |
1522 |
1523 | Type: 1524 |
1525 |
1526 | 1527 | MarkdownNode 1528 | 1529 | 1530 |
1531 |
1532 | 1533 | 1534 | 1535 |
1536 | 1537 | 1538 | 1539 |
1540 | 1541 | 1542 |
1543 | 1544 | 1545 | 1546 |

type() → {String}

1547 | 1548 | 1549 | 1550 | 1551 | 1552 |
1553 | Returns the type of the node you're currently on. 1554 |
1555 | 1556 | 1557 | 1558 | 1559 | 1560 |
1561 | 1562 | 1563 | 1564 | 1565 | 1566 | 1567 | 1568 | 1569 | 1570 | 1571 | 1572 | 1573 | 1574 | 1575 | 1576 | 1577 | 1578 | 1579 | 1580 | 1581 | 1582 | 1583 | 1584 | 1585 | 1586 | 1587 |
Source:
1588 |
1591 | 1592 | 1593 | 1594 | 1595 | 1596 | 1597 | 1598 |
1599 | 1600 | 1601 | 1602 | 1603 | 1604 | 1605 | 1606 | 1607 | 1608 | 1609 | 1610 | 1611 | 1612 | 1613 | 1614 | 1615 | 1616 | 1617 | 1618 | 1619 | 1620 |
1621 |
Returns:
1622 | 1623 | 1624 | 1625 |
1626 |
1627 | Type: 1628 |
1629 |
1630 | 1631 | String 1632 | 1633 | 1634 |
1635 |
1636 | 1637 | 1638 |
1639 | the type of node you're currently on. 1640 |
1641 | 1642 | 1643 |
1644 | 1645 | 1646 | 1647 |
1648 |
Examples
1649 | 1650 |
mrk("# Hello").heading().type(); // Returns "heading"
1651 | 1652 |
mark("Im a paragraph").paragraph().type(); // Returns "paragraph"
1653 | 1654 |
mrk("hello").type(); // Returns "root"
1655 | 1656 |
1657 | 1658 |
1659 | 1660 | 1661 |
1662 | 1663 | 1664 | 1665 |

value() → {String}

1666 | 1667 | 1668 | 1669 | 1670 | 1671 |
1672 | Returns the value of the node you're on. 1673 | If get() returns the markdown string of where you're at, this 1674 | returns the actual value of where you're at. 1675 |
1676 | 1677 | 1678 | 1679 | 1680 | 1681 |
1682 | 1683 | 1684 | 1685 | 1686 | 1687 | 1688 | 1689 | 1690 | 1691 | 1692 | 1693 | 1694 | 1695 | 1696 | 1697 | 1698 | 1699 | 1700 | 1701 | 1702 | 1703 | 1704 | 1705 | 1706 | 1707 | 1708 |
Source:
1709 |
1712 | 1713 | 1714 | 1715 | 1716 | 1717 | 1718 | 1719 |
1720 | 1721 | 1722 | 1723 | 1724 | 1725 | 1726 | 1727 | 1728 | 1729 | 1730 | 1731 | 1732 | 1733 | 1734 | 1735 | 1736 | 1737 | 1738 | 1739 | 1740 | 1741 |
1742 |
Returns:
1743 | 1744 | 1745 | 1746 |
1747 |
1748 | Type: 1749 |
1750 |
1751 | 1752 | String 1753 | 1754 | 1755 |
1756 |
1757 | 1758 | 1759 |
1760 | The string value of the node you're on. 1761 |
1762 | 1763 | 1764 |
1765 | 1766 | 1767 | 1768 |
1769 |
Examples
1770 | 1771 |
mrk("# Hello I am header").value(); // Returns "Hello I am header"
1772 | 1773 |
var m = mrk("# Hello I am header");
1774 | const isTrue = m.get() != m.value(); // True
1775 | 1776 |
1777 | 1778 |
1779 | 1780 | 1781 | 1782 | 1783 | 1784 | 1785 |
1786 | 1787 |
1788 | 1789 | 1790 | 1791 | 1792 |
1793 | 1794 |
1795 | 1796 | 1799 | 1800 | 1801 | 1802 | 1803 | -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Bold-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Flaque/mark-dom/399e5d22791f5e1b1191a361f41f13cb13062671/docs/fonts/OpenSans-Bold-webfont.eot -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Bold-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Flaque/mark-dom/399e5d22791f5e1b1191a361f41f13cb13062671/docs/fonts/OpenSans-Bold-webfont.woff -------------------------------------------------------------------------------- /docs/fonts/OpenSans-BoldItalic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Flaque/mark-dom/399e5d22791f5e1b1191a361f41f13cb13062671/docs/fonts/OpenSans-BoldItalic-webfont.eot -------------------------------------------------------------------------------- /docs/fonts/OpenSans-BoldItalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Flaque/mark-dom/399e5d22791f5e1b1191a361f41f13cb13062671/docs/fonts/OpenSans-BoldItalic-webfont.woff -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Italic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Flaque/mark-dom/399e5d22791f5e1b1191a361f41f13cb13062671/docs/fonts/OpenSans-Italic-webfont.eot -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Italic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Flaque/mark-dom/399e5d22791f5e1b1191a361f41f13cb13062671/docs/fonts/OpenSans-Italic-webfont.woff -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Light-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Flaque/mark-dom/399e5d22791f5e1b1191a361f41f13cb13062671/docs/fonts/OpenSans-Light-webfont.eot -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Light-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Flaque/mark-dom/399e5d22791f5e1b1191a361f41f13cb13062671/docs/fonts/OpenSans-Light-webfont.woff -------------------------------------------------------------------------------- /docs/fonts/OpenSans-LightItalic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Flaque/mark-dom/399e5d22791f5e1b1191a361f41f13cb13062671/docs/fonts/OpenSans-LightItalic-webfont.eot -------------------------------------------------------------------------------- /docs/fonts/OpenSans-LightItalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Flaque/mark-dom/399e5d22791f5e1b1191a361f41f13cb13062671/docs/fonts/OpenSans-LightItalic-webfont.woff -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Regular-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Flaque/mark-dom/399e5d22791f5e1b1191a361f41f13cb13062671/docs/fonts/OpenSans-Regular-webfont.eot -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Regular-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Flaque/mark-dom/399e5d22791f5e1b1191a361f41f13cb13062671/docs/fonts/OpenSans-Regular-webfont.woff -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Semibold-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Flaque/mark-dom/399e5d22791f5e1b1191a361f41f13cb13062671/docs/fonts/OpenSans-Semibold-webfont.eot -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Semibold-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Flaque/mark-dom/399e5d22791f5e1b1191a361f41f13cb13062671/docs/fonts/OpenSans-Semibold-webfont.ttf -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Semibold-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Flaque/mark-dom/399e5d22791f5e1b1191a361f41f13cb13062671/docs/fonts/OpenSans-Semibold-webfont.woff -------------------------------------------------------------------------------- /docs/fonts/OpenSans-SemiboldItalic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Flaque/mark-dom/399e5d22791f5e1b1191a361f41f13cb13062671/docs/fonts/OpenSans-SemiboldItalic-webfont.eot -------------------------------------------------------------------------------- /docs/fonts/OpenSans-SemiboldItalic-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Flaque/mark-dom/399e5d22791f5e1b1191a361f41f13cb13062671/docs/fonts/OpenSans-SemiboldItalic-webfont.ttf -------------------------------------------------------------------------------- /docs/fonts/OpenSans-SemiboldItalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Flaque/mark-dom/399e5d22791f5e1b1191a361f41f13cb13062671/docs/fonts/OpenSans-SemiboldItalic-webfont.woff -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Home - Documentation 7 | 8 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 23 | 24 | 25 | 26 | 29 | 30 |
31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 |
51 |

mark-dom

Build Status 52 | Coverage Status

53 |

Mark-dom is basically jQuery but for markdown.

54 |

If you've ever wanted to write a script that only edits a single part of a markdown doc and leaves the rest alone, then hopefully this brings you joy.

55 |

Docs Here.

56 |

Install

$ npm install mark-dom

Example

Our Example Markdown

<!-- This is some markdown -->
 57 | # Hello there
 58 | I am some markdown
 59 | 
 60 | ## Dogs are cool
 61 | They bring you friendly joy.
 62 | 
 63 | ## World peace is cool
 64 | Let's bake some cakes and be nice to each other

Get a header value

import mrk = require("mark-dom");
 65 | 
 66 | // Returns "World peace is cool"
 67 | mrk(thatMarkdownStr)
 68 |     .heading("## World peace *")
 69 |     .value();

Change a header

import mrk = require("mark-dom");
 70 | 
 71 | // Return a new markdown string where the first header 
 72 | // is "Stuff that's cool"
 73 | mrk(thatMarkdownStr)
 74 |     .heading() // gets the first heading!
 75 |     .set("Stuff that's cool");
 76 |     .getAll();

Change an entire paragraph

import mrk = require("mark-dom");
 77 | 
 78 | // Change the "dogs" header and return a new markdown string
 79 | mrk(thatMarkdownStr)
 80 |     .heading("## * ") // Get the first sub header
 81 |     .paragraph()
 82 |     .set("They make you smile.")
 83 |     .getAll();

Status

Mark-dom is really just an experiment at the moment and I haven't really fleshed out all of the API that I want yet. Things might change, at the time that I'm writing this, I don't think it even works.

84 |

TODO list

    85 |
  • ~Glob syntax *~
  • 86 |
  • Find tables
  • 87 |
  • Find code
  • 88 |
  • Find lists
  • 89 |
  • Putting a 2d array in set() will create a table
  • 90 |
  • Putting a 1d array in set() will create a list
  • 91 |
92 |

How's it work?

Mark-dom uses remark and it's ecosystem to parse the markdown into an Abstract Syntax Tree (AST), then it lets you navigate and edit the tree with an API and eventually construct a new markdown document by compiling the tree down to a string.

93 |

What's the use case?

    94 |
  • Auto-generating README's
  • 95 |
  • Forcing standards/style-guides to docs
  • 96 |
  • ???
  • 97 |
  • Profit!
  • 98 |
99 |
100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 |
110 | 111 |
112 | 113 |

114 | markdown.js 115 |

116 | 117 | 118 |
119 | 120 |
121 |
122 | 123 | 124 |
Defines a MarkdownNode, the main abstraction for the Markdown AST.
125 | 126 | 127 | 128 | 129 | 130 |
131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 |
Source:
158 |
161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 |
169 | 170 | 171 | 172 | 173 |
174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 |
193 | 194 |
195 | 196 | 197 | 198 | 199 |
200 | 201 |
202 | 203 | 206 | 207 | 208 | 209 | 210 | -------------------------------------------------------------------------------- /docs/markdown.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | markdown.js - Documentation 7 | 8 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 23 | 24 | 25 | 26 | 29 | 30 |
31 | 32 |

markdown.js

33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 |
41 |
42 |
/**
 43 |  * @file Defines a MarkdownNode, the main abstraction for the Markdown AST.
 44 |  */
 45 | const makeTable = require("markdown-table");
 46 | const remark = require("remark");
 47 | const stringify = require("remark-stringify");
 48 | const _ = require("lodash");
 49 | const error = require("./error.js");
 50 | const { types } = require("./constants.js");
 51 | const query = require("./query");
 52 | 
 53 | /**
 54 |  * Helpers
 55 |  */
 56 | 
 57 | /**
 58 |  * @private
 59 |  */
 60 | function throwIfNotExist(component, type) {
 61 |   if (!component) throw error.doesNotExist(type);
 62 | }
 63 | 
 64 | /**
 65 |  * A MarkdownNode is an object describing a node in the 
 66 |  * Abstract Syntax Tree (AST) of the markdown.
 67 |  * 
 68 |  * @example 
 69 |  * import mrk = require("mark-dom");
 70 |  * mrk("# Hello").get(); // Will return "# Hello"
 71 |  * 
 72 |  */
 73 | class MarkdownNode {
 74 |   /**
 75 |    * A markdown node takes either an Abstract Syntax Tree (AST)
 76 |    * or a markdown string.
 77 |    * 
 78 |    * @param {ast|string} src The markdown string that we'll parse into an AST.
 79 |    * @param {JSON} [options] Options to be passed into MarkdownNode
 80 |    */
 81 |   constructor(src, options) {
 82 |     if (typeof src === "object") {
 83 |       this._ast = options._ast;
 84 |       this._pointer = src;
 85 |     } else if (typeof src === "string") {
 86 |       this._ast = remark().parse(src);
 87 |       this._pointer = this._ast;
 88 |     } else if (typeof src === "undefined") {
 89 |       this._ast = remark().parse(""); // treat undefined like an empty string.
 90 |       this._pointer = this._ast;
 91 |     } else {
 92 |       throw error.badMarkdownSrc();
 93 |     }
 94 |   }
 95 | 
 96 |   /**
 97 |    * Returns the markdown string version of the node you're currently on.
 98 |    * 
 99 |    * @example
100 |    * // Returns "## Subheader"
101 |    * mrk(`
102 |    * # Hello
103 |    * ## Subheader
104 |    * `).heading("## *").get();
105 |    * 
106 |    * @return {String} The String version of the CURRENT node we're on. 
107 |    */
108 |   get() {
109 |     return remark().use(stringify).stringify(this._pointer).trim();
110 |   }
111 | 
112 |   /**
113 |    * Returns the markdown string version of the entire AST of this piece of 
114 |    * markdown.
115 |    * @return {String} The String version of the ENTIRE compiled Markdown AST.
116 |    */
117 |   getAll() {
118 |     return remark().use(stringify).stringify(this._ast).trim();
119 |   }
120 | 
121 |   /**
122 |    * Gets a new MarkdownNode representing an aribtary AST type.
123 |    * 
124 |    * @example
125 |    * // Returns "# Hello"
126 |    * mrk().set("# Hello").search("# H*").getAll();
127 |    * 
128 |    * @param {String} 
129 |    * @param {String} [searchWord] A string to search for in the node. Can use wildcard * syntax.
130 |    */
131 |   search(type, searchWord) {
132 |     const node = searchWord
133 |       ? query.where(this._ast, type, searchWord)
134 |       : query.first(this._ast, type);
135 | 
136 |     throwIfNotExist(node, type);
137 |     return new MarkdownNode(node, { _ast: this._ast });
138 |   }
139 | 
140 |   /**
141 |    * Gets a new MarkdownNode representing the first heading it finds.
142 |    * 
143 |    * @example 
144 |    * // Returns a MarkdownNode at the heading.
145 |    * mrk("# Hello").heading("H*");
146 |    * 
147 |    * @example 
148 |    * // Returns a MarkdownNode representing "# First"
149 |    * mrk(`
150 |    * # First 
151 |    * some text
152 |    * 
153 |    * # Second
154 |    * other text
155 |    * `).heading();
156 |    * 
157 |    * @param {String} [searchWord] A string to search for in the heading. Can use wildcard * syntax.
158 |    * @return {MarkdownNode} A new child node at the next heading.
159 |    */
160 |   heading(searchWord) {
161 |     return this.search(types.HEADING, searchWord);
162 |   }
163 | 
164 |   /**
165 |    * Gets a new MarkdownNode representing the first paragraph it finds.
166 |    * 
167 |    * @example 
168 |    * // Returns a MarkdownNode at the paragraph.
169 |    * mrk("Hello").paragraph("H*");
170 |    * 
171 |    * @example 
172 |    * // Returns a MarkdownNode representing "First Paragraph"
173 |    * mrk(`
174 |    * # First 
175 |    * First Paragraph
176 |    * 
177 |    * # Second
178 |    * Second Paragraph
179 |    * `).paragraph();
180 |    * 
181 |    * @param {String} [searchWord] A string to search for in the paragraph. Can use wildcard * syntax.
182 |    * @return {MarkdownNode}
183 |    */
184 |   paragraph(searchWord) {
185 |     return this.search(types.PARAGRAPH, searchWord);
186 |   }
187 | 
188 |   /**
189 |    * Gets a new MarkdownNode representing the first paragraph it finds 
190 |    *
191 |    * 
192 |    * @param {String} [searchWord] A string to search for somewhere in the table. Can use wildcard * syntax.
193 |    * @return {MarkdownNode}
194 |    */
195 |   table(searchWord) {
196 |     return this.search(types.TABLE, searchWord);
197 |   }
198 | 
199 |   /**
200 |    * Create a markdown table from an array.
201 |    * @param {Array} array 
202 |    * @return {MarkdownNode}
203 |    */
204 |   setTable(array) {
205 |     const tableAST = remark().parse(makeTable(array));
206 |     const wrappedTable = new MarkdownNode(remark().parse(array), {
207 |       _ast: tableAST
208 |     });
209 | 
210 |     this._pointer.children = []; // THIS IS PRETTY BAD.
211 |     this._pointer.children.push(wrappedTable.table()._pointer); // TODO: HMMM THIS SEEMS FISHY. PROBABLY SHOULD CLEAR SOME STUFF FIRST
212 | 
213 |     return new MarkdownNode(this._pointer, { _ast: this._ast });
214 |   }
215 | 
216 |   /**
217 |    * Sets the current node's value to the str input
218 |    * @param {String} str 
219 |    * @return {MarkdownNode}
220 |    */
221 |   set(str) {
222 |     // In the case that this node is empty, create something new!
223 |     if (_.isEmpty(this._pointer.children)) {
224 |       this._pointer = this._ast = remark().parse(str);
225 |       return new MarkdownNode(this._pointer, { _ast: this._ast });
226 |     }
227 | 
228 |     this._pointer.children[0].value = str; // TODO: This is probably going to have some weird effects.
229 |     return new MarkdownNode(this._pointer, { _ast: this._ast });
230 |   }
231 | 
232 |   /**
233 |    * Returns the type of the node you're currently on.
234 |    * 
235 |    * @example 
236 |    * mrk("# Hello").heading().type(); // Returns "heading"
237 |    * 
238 |    * @example
239 |    * mark("Im a paragraph").paragraph().type(); // Returns "paragraph"
240 |    * 
241 |    * @example
242 |    * mrk("hello").type(); // Returns "root"
243 |    * 
244 |    * @return {String} the type of node you're currently on. 
245 |    */
246 |   type() {
247 |     return this._pointer.type;
248 |   }
249 | 
250 |   /**
251 |    * Returns the value of the node you're on.
252 |    * If get() returns the markdown string of where you're at, this 
253 |    * returns the actual value of where you're at. 
254 |    * 
255 |    * @example
256 |    * mrk("# Hello I am header").value(); // Returns "Hello I am header"
257 |    * 
258 |    * @example
259 |    * var m = mrk("# Hello I am header");
260 |    * const isTrue = m.get() != m.value(); // True
261 |    * 
262 |    * @return {String} The string value of the node you're on.
263 |    */
264 |   value() {
265 |     return this._pointer.children[0].value; // this is probably gonna have some weird effects.
266 |   }
267 | }
268 | 
269 | module.exports = MarkdownNode;
270 | 
271 |
272 |
273 | 274 | 275 | 276 | 277 |
278 | 279 |
280 | 281 | 284 | 285 | 286 | 287 | 288 | 289 | -------------------------------------------------------------------------------- /docs/scripts/linenumber.js: -------------------------------------------------------------------------------- 1 | /*global document */ 2 | (function() { 3 | var source = document.getElementsByClassName('prettyprint source linenums'); 4 | var i = 0; 5 | var lineNumber = 0; 6 | var lineId; 7 | var lines; 8 | var totalLines; 9 | var anchorHash; 10 | 11 | if (source && source[0]) { 12 | anchorHash = document.location.hash.substring(1); 13 | lines = source[0].getElementsByTagName('li'); 14 | totalLines = lines.length; 15 | 16 | for (; i < totalLines; i++) { 17 | lineNumber++; 18 | lineId = 'line' + lineNumber; 19 | lines[i].id = lineId; 20 | if (lineId === anchorHash) { 21 | lines[i].className += ' selected'; 22 | } 23 | } 24 | } 25 | })(); 26 | -------------------------------------------------------------------------------- /docs/scripts/prettify/Apache-License-2.0.txt: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /docs/scripts/prettify/lang-css.js: -------------------------------------------------------------------------------- 1 | PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\f\r ]+/,null," \t\r\n "]],[["str",/^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/,null],["str",/^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/,null],["lang-css-str",/^url\(([^"')]*)\)/i],["kwd",/^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i],["com",/^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//],["com", 2 | /^(?:<\!--|--\>)/],["lit",/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],["lit",/^#[\da-f]{3,6}/i],["pln",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i],["pun",/^[^\s\w"']+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[["kwd",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[["str",/^[^"')]+/]]),["css-str"]); 3 | -------------------------------------------------------------------------------- /docs/scripts/prettify/prettify.js: -------------------------------------------------------------------------------- 1 | var q=null;window.PR_SHOULD_USE_CONTINUATION=!0; 2 | (function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a= 3 | [],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;ci[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m), 9 | l=[],p={},d=0,g=e.length;d=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/, 10 | q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/, 11 | q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g, 12 | "");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a), 13 | a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e} 14 | for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"], 18 | "catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"], 19 | H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"], 20 | J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+ 21 | I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]), 22 | ["default-markup","htm","html","mxml","xhtml","xml","xsl"]);k(x([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css", 23 | /^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);k(x([],[["atv",/^[\S\s]+/]]),["uq.val"]);k(u({keywords:F,hashComments:!0,cStyleComments:!0,types:K}),["c","cc","cpp","cxx","cyc","m"]);k(u({keywords:"null,true,false"}),["json"]);k(u({keywords:H,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:K}),["cs"]);k(u({keywords:G,cStyleComments:!0}),["java"]);k(u({keywords:v,hashComments:!0,multiLineStrings:!0}),["bsh","csh","sh"]);k(u({keywords:I,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}), 24 | ["cv","py"]);k(u({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["perl","pl","pm"]);k(u({keywords:J,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb"]);k(u({keywords:w,cStyleComments:!0,regexLiterals:!0}),["js"]);k(u({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes", 25 | hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);k(x([],[["str",/^[\S\s]+/]]),["regex"]);window.prettyPrintOne=function(a,m,e){var h=document.createElement("PRE");h.innerHTML=a;e&&D(h,e);E({g:m,i:e,h:h});return h.innerHTML};window.prettyPrint=function(a){function m(){for(var e=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;p=0){var k=k.match(g),f,b;if(b= 26 | !k){b=n;for(var o=void 0,c=b.firstChild;c;c=c.nextSibling)var i=c.nodeType,o=i===1?o?b:c:i===3?N.test(c.nodeValue)?b:o:o;b=(f=o===b?void 0:o)&&"CODE"===f.tagName}b&&(k=f.className.match(g));k&&(k=k[1]);b=!1;for(o=n.parentNode;o;o=o.parentNode)if((o.tagName==="pre"||o.tagName==="code"||o.tagName==="xmp")&&o.className&&o.className.indexOf("prettyprint")>=0){b=!0;break}b||((b=(b=n.className.match(/\blinenums\b(?::(\d+))?/))?b[1]&&b[1].length?+b[1]:!0:!1)&&D(n,b),d={g:k,h:n,i:b},E(d))}}p code { 197 | font-size: 0.85em; 198 | } 199 | 200 | .readme table { 201 | margin-bottom: 1em; 202 | border-collapse: collapse; 203 | border-spacing: 0; 204 | } 205 | 206 | .readme table tr { 207 | background-color: #fff; 208 | border-top: 1px solid #ccc; 209 | } 210 | 211 | .readme table th, 212 | .readme table td { 213 | padding: 6px 13px; 214 | border: 1px solid #ddd; 215 | } 216 | 217 | .readme table tr:nth-child(2n) { 218 | background-color: #f8f8f8; 219 | } 220 | 221 | /** Nav **/ 222 | nav { 223 | float: left; 224 | display: block; 225 | width: 250px; 226 | background: #fff; 227 | overflow: auto; 228 | position: fixed; 229 | height: 100%; 230 | padding: 10px; 231 | border-right: 1px solid #eee; 232 | /* box-shadow: 0 0 3px rgba(0,0,0,0.1); */ 233 | } 234 | 235 | nav li { 236 | list-style: none; 237 | padding: 0; 238 | margin: 0; 239 | } 240 | 241 | .nav-heading { 242 | margin-top: 10px; 243 | font-weight: bold; 244 | } 245 | 246 | .nav-heading a { 247 | color: #888; 248 | font-size: 14px; 249 | display: inline-block; 250 | } 251 | 252 | .nav-item-type { 253 | /* margin-left: 5px; */ 254 | width: 18px; 255 | height: 18px; 256 | display: inline-block; 257 | text-align: center; 258 | border-radius: 0.2em; 259 | margin-right: 5px; 260 | font-weight: bold; 261 | line-height: 20px; 262 | font-size: 13px; 263 | } 264 | 265 | .type-function { 266 | background: #B3E5FC; 267 | color: #0288D1; 268 | } 269 | 270 | .type-class { 271 | background: #D1C4E9; 272 | color: #4527A0; 273 | } 274 | 275 | .type-member { 276 | background: #C8E6C9; 277 | color: #388E3C; 278 | } 279 | 280 | .type-module { 281 | background: #E1BEE7; 282 | color: #7B1FA2; 283 | } 284 | 285 | 286 | /** Footer **/ 287 | footer { 288 | color: hsl(0, 0%, 28%); 289 | margin-left: 250px; 290 | display: block; 291 | padding: 30px; 292 | font-style: italic; 293 | font-size: 90%; 294 | border-top: 1px solid #eee; 295 | } 296 | 297 | .ancestors { 298 | color: #999 299 | } 300 | 301 | .ancestors a { 302 | color: #999 !important; 303 | text-decoration: none; 304 | } 305 | 306 | .clear { 307 | clear: both 308 | } 309 | 310 | .important { 311 | font-weight: bold; 312 | color: #950B02; 313 | } 314 | 315 | .yes-def { 316 | text-indent: -1000px 317 | } 318 | 319 | .type-signature { 320 | color: #aaa 321 | } 322 | 323 | .name, .signature { 324 | font-family: Consolas, Monaco, 'Andale Mono', monospace 325 | } 326 | 327 | .details { 328 | margin-top: 14px; 329 | border-left: 2px solid #DDD; 330 | line-height: 30px; 331 | } 332 | 333 | .details dt { 334 | width: 120px; 335 | float: left; 336 | padding-left: 10px; 337 | } 338 | 339 | .details dd { 340 | margin-left: 70px 341 | } 342 | 343 | .details ul { 344 | margin: 0 345 | } 346 | 347 | .details ul { 348 | list-style-type: none 349 | } 350 | 351 | .details li { 352 | margin-left: 30px 353 | } 354 | 355 | .details pre.prettyprint { 356 | margin: 0 357 | } 358 | 359 | .details .object-value { 360 | padding-top: 0 361 | } 362 | 363 | .description { 364 | margin-bottom: 1em; 365 | margin-top: 1em; 366 | } 367 | 368 | .code-caption { 369 | font-style: italic; 370 | font-size: 107%; 371 | margin: 0; 372 | } 373 | 374 | .prettyprint { 375 | font-size: 13px; 376 | border: 1px solid #ddd; 377 | border-radius: 3px; 378 | box-shadow: 0 1px 3px hsla(0, 0%, 0%, 0.05); 379 | overflow: auto; 380 | } 381 | 382 | .prettyprint.source { 383 | width: inherit 384 | } 385 | 386 | .prettyprint code { 387 | font-size: 12px; 388 | line-height: 18px; 389 | display: block; 390 | background-color: #fff; 391 | color: #4D4E53; 392 | } 393 | 394 | .prettyprint code:empty:before { 395 | content: ''; 396 | } 397 | 398 | .prettyprint > code { 399 | padding: 15px 400 | } 401 | 402 | .prettyprint .linenums code { 403 | padding: 0 15px 404 | } 405 | 406 | .prettyprint .linenums li:first-of-type code { 407 | padding-top: 15px 408 | } 409 | 410 | .prettyprint code span.line { 411 | display: inline-block 412 | } 413 | 414 | .prettyprint.linenums { 415 | padding-left: 70px; 416 | -webkit-user-select: none; 417 | -moz-user-select: none; 418 | -ms-user-select: none; 419 | user-select: none; 420 | } 421 | 422 | .prettyprint.linenums ol { 423 | padding-left: 0 424 | } 425 | 426 | .prettyprint.linenums li { 427 | border-left: 3px #ddd solid 428 | } 429 | 430 | .prettyprint.linenums li.selected, .prettyprint.linenums li.selected * { 431 | background-color: lightyellow 432 | } 433 | 434 | .prettyprint.linenums li * { 435 | -webkit-user-select: text; 436 | -moz-user-select: text; 437 | -ms-user-select: text; 438 | user-select: text; 439 | } 440 | 441 | .params, .props { 442 | border-spacing: 0; 443 | border: 1px solid #ddd; 444 | border-collapse: collapse; 445 | border-radius: 3px; 446 | box-shadow: 0 1px 3px rgba(0,0,0,0.1); 447 | width: 100%; 448 | font-size: 14px; 449 | /* margin-left: 15px; */ 450 | } 451 | 452 | .params .name, .props .name, .name code { 453 | color: #4D4E53; 454 | font-family: Consolas, Monaco, 'Andale Mono', monospace; 455 | font-size: 100%; 456 | } 457 | 458 | .params td, .params th, .props td, .props th { 459 | margin: 0px; 460 | text-align: left; 461 | vertical-align: top; 462 | padding: 10px; 463 | display: table-cell; 464 | } 465 | 466 | .params td { 467 | border-top: 1px solid #eee 468 | } 469 | 470 | .params thead tr, .props thead tr { 471 | background-color: #fff; 472 | font-weight: bold; 473 | } 474 | 475 | .params .params thead tr, .props .props thead tr { 476 | background-color: #fff; 477 | font-weight: bold; 478 | } 479 | 480 | .params td.description > p:first-child, .props td.description > p:first-child { 481 | margin-top: 0; 482 | padding-top: 0; 483 | } 484 | 485 | .params td.description > p:last-child, .props td.description > p:last-child { 486 | margin-bottom: 0; 487 | padding-bottom: 0; 488 | } 489 | 490 | dl.param-type { 491 | /* border-bottom: 1px solid hsl(0, 0%, 87%); */ 492 | margin: 0; 493 | padding: 0; 494 | font-size: 16px; 495 | } 496 | 497 | .param-type dt, .param-type dd { 498 | display: inline-block 499 | } 500 | 501 | .param-type dd { 502 | font-family: Consolas, Monaco, 'Andale Mono', monospace; 503 | display: inline-block; 504 | padding: 0; 505 | margin: 0; 506 | font-size: 14px; 507 | } 508 | 509 | .disabled { 510 | color: #454545 511 | } 512 | 513 | /* navicon button */ 514 | .navicon-button { 515 | display: none; 516 | position: relative; 517 | padding: 2.0625rem 1.5rem; 518 | transition: 0.25s; 519 | cursor: pointer; 520 | user-select: none; 521 | opacity: .8; 522 | } 523 | .navicon-button .navicon:before, .navicon-button .navicon:after { 524 | transition: 0.25s; 525 | } 526 | .navicon-button:hover { 527 | transition: 0.5s; 528 | opacity: 1; 529 | } 530 | .navicon-button:hover .navicon:before, .navicon-button:hover .navicon:after { 531 | transition: 0.25s; 532 | } 533 | .navicon-button:hover .navicon:before { 534 | top: .825rem; 535 | } 536 | .navicon-button:hover .navicon:after { 537 | top: -.825rem; 538 | } 539 | 540 | /* navicon */ 541 | .navicon { 542 | position: relative; 543 | width: 2.5em; 544 | height: .3125rem; 545 | background: #000; 546 | transition: 0.3s; 547 | border-radius: 2.5rem; 548 | } 549 | .navicon:before, .navicon:after { 550 | display: block; 551 | content: ""; 552 | height: .3125rem; 553 | width: 2.5rem; 554 | background: #000; 555 | position: absolute; 556 | z-index: -1; 557 | transition: 0.3s 0.25s; 558 | border-radius: 1rem; 559 | } 560 | .navicon:before { 561 | top: .625rem; 562 | } 563 | .navicon:after { 564 | top: -.625rem; 565 | } 566 | 567 | /* open */ 568 | .nav-trigger:checked + label:not(.steps) .navicon:before, 569 | .nav-trigger:checked + label:not(.steps) .navicon:after { 570 | top: 0 !important; 571 | } 572 | 573 | .nav-trigger:checked + label .navicon:before, 574 | .nav-trigger:checked + label .navicon:after { 575 | transition: 0.5s; 576 | } 577 | 578 | /* Minus */ 579 | .nav-trigger:checked + label { 580 | transform: scale(0.75); 581 | } 582 | 583 | /* × and + */ 584 | .nav-trigger:checked + label.plus .navicon, 585 | .nav-trigger:checked + label.x .navicon { 586 | background: transparent; 587 | } 588 | 589 | .nav-trigger:checked + label.plus .navicon:before, 590 | .nav-trigger:checked + label.x .navicon:before { 591 | transform: rotate(-45deg); 592 | background: #FFF; 593 | } 594 | 595 | .nav-trigger:checked + label.plus .navicon:after, 596 | .nav-trigger:checked + label.x .navicon:after { 597 | transform: rotate(45deg); 598 | background: #FFF; 599 | } 600 | 601 | .nav-trigger:checked + label.plus { 602 | transform: scale(0.75) rotate(45deg); 603 | } 604 | 605 | .nav-trigger:checked ~ nav { 606 | left: 0 !important; 607 | } 608 | 609 | .nav-trigger:checked ~ .overlay { 610 | display: block; 611 | } 612 | 613 | .nav-trigger { 614 | position: fixed; 615 | top: 0; 616 | clip: rect(0, 0, 0, 0); 617 | } 618 | 619 | .overlay { 620 | display: none; 621 | position: fixed; 622 | top: 0; 623 | bottom: 0; 624 | left: 0; 625 | right: 0; 626 | width: 100%; 627 | height: 100%; 628 | background: hsla(0, 0%, 0%, 0.5); 629 | z-index: 1; 630 | } 631 | 632 | .section-method { 633 | margin-bottom: 30px; 634 | padding-bottom: 30px; 635 | border-bottom: 1px solid #eee; 636 | } 637 | 638 | @media only screen and (min-width: 320px) and (max-width: 680px) { 639 | body { 640 | overflow-x: hidden; 641 | } 642 | 643 | nav { 644 | background: #FFF; 645 | width: 250px; 646 | height: 100%; 647 | position: fixed; 648 | top: 0; 649 | right: 0; 650 | bottom: 0; 651 | left: -250px; 652 | z-index: 3; 653 | padding: 0 10px; 654 | transition: left 0.2s; 655 | } 656 | 657 | .navicon-button { 658 | display: inline-block; 659 | position: fixed; 660 | top: 1.5em; 661 | right: 0; 662 | z-index: 2; 663 | } 664 | 665 | #main { 666 | width: 100%; 667 | min-width: 360px; 668 | } 669 | 670 | #main h1.page-title { 671 | margin: 1em 0; 672 | } 673 | 674 | #main section { 675 | padding: 0; 676 | } 677 | 678 | footer { 679 | margin-left: 0; 680 | } 681 | } 682 | 683 | @media only print { 684 | nav { 685 | display: none; 686 | } 687 | 688 | #main { 689 | float: none; 690 | width: 100%; 691 | } 692 | } 693 | -------------------------------------------------------------------------------- /docs/styles/prettify-jsdoc.css: -------------------------------------------------------------------------------- 1 | /* JSDoc prettify.js theme */ 2 | 3 | /* plain text */ 4 | .pln { 5 | color: #000000; 6 | font-weight: normal; 7 | font-style: normal; 8 | } 9 | 10 | /* string content */ 11 | .str { 12 | color: hsl(104, 100%, 24%); 13 | font-weight: normal; 14 | font-style: normal; 15 | } 16 | 17 | /* a keyword */ 18 | .kwd { 19 | color: #000000; 20 | font-weight: bold; 21 | font-style: normal; 22 | } 23 | 24 | /* a comment */ 25 | .com { 26 | font-weight: normal; 27 | font-style: italic; 28 | } 29 | 30 | /* a type name */ 31 | .typ { 32 | color: #000000; 33 | font-weight: normal; 34 | font-style: normal; 35 | } 36 | 37 | /* a literal value */ 38 | .lit { 39 | color: #006400; 40 | font-weight: normal; 41 | font-style: normal; 42 | } 43 | 44 | /* punctuation */ 45 | .pun { 46 | color: #000000; 47 | font-weight: bold; 48 | font-style: normal; 49 | } 50 | 51 | /* lisp open bracket */ 52 | .opn { 53 | color: #000000; 54 | font-weight: bold; 55 | font-style: normal; 56 | } 57 | 58 | /* lisp close bracket */ 59 | .clo { 60 | color: #000000; 61 | font-weight: bold; 62 | font-style: normal; 63 | } 64 | 65 | /* a markup tag name */ 66 | .tag { 67 | color: #006400; 68 | font-weight: normal; 69 | font-style: normal; 70 | } 71 | 72 | /* a markup attribute name */ 73 | .atn { 74 | color: #006400; 75 | font-weight: normal; 76 | font-style: normal; 77 | } 78 | 79 | /* a markup attribute value */ 80 | .atv { 81 | color: #006400; 82 | font-weight: normal; 83 | font-style: normal; 84 | } 85 | 86 | /* a declaration */ 87 | .dec { 88 | color: #000000; 89 | font-weight: bold; 90 | font-style: normal; 91 | } 92 | 93 | /* a variable name */ 94 | .var { 95 | color: #000000; 96 | font-weight: normal; 97 | font-style: normal; 98 | } 99 | 100 | /* a function name */ 101 | .fun { 102 | color: #000000; 103 | font-weight: bold; 104 | font-style: normal; 105 | } 106 | 107 | /* Specify class=linenums on a pre to get line numbering */ 108 | ol.linenums { 109 | margin-top: 0; 110 | margin-bottom: 0; 111 | } 112 | -------------------------------------------------------------------------------- /docs/styles/prettify-tomorrow.css: -------------------------------------------------------------------------------- 1 | /* Tomorrow Theme */ 2 | /* Original theme - https://github.com/chriskempson/tomorrow-theme */ 3 | /* Pretty printing styles. Used with prettify.js. */ 4 | /* SPAN elements with the classes below are added by prettyprint. */ 5 | /* plain text */ 6 | .pln { 7 | color: #4d4d4c; } 8 | 9 | @media screen { 10 | /* string content */ 11 | .str { 12 | color: hsl(104, 100%, 24%); } 13 | 14 | /* a keyword */ 15 | .kwd { 16 | color: hsl(240, 100%, 50%); } 17 | 18 | /* a comment */ 19 | .com { 20 | color: hsl(0, 0%, 60%); } 21 | 22 | /* a type name */ 23 | .typ { 24 | color: hsl(240, 100%, 32%); } 25 | 26 | /* a literal value */ 27 | .lit { 28 | color: hsl(240, 100%, 40%); } 29 | 30 | /* punctuation */ 31 | .pun { 32 | color: #000000; } 33 | 34 | /* lisp open bracket */ 35 | .opn { 36 | color: #000000; } 37 | 38 | /* lisp close bracket */ 39 | .clo { 40 | color: #000000; } 41 | 42 | /* a markup tag name */ 43 | .tag { 44 | color: #c82829; } 45 | 46 | /* a markup attribute name */ 47 | .atn { 48 | color: #f5871f; } 49 | 50 | /* a markup attribute value */ 51 | .atv { 52 | color: #3e999f; } 53 | 54 | /* a declaration */ 55 | .dec { 56 | color: #f5871f; } 57 | 58 | /* a variable name */ 59 | .var { 60 | color: #c82829; } 61 | 62 | /* a function name */ 63 | .fun { 64 | color: #4271ae; } } 65 | /* Use higher contrast and text-weight for printable form. */ 66 | @media print, projection { 67 | .str { 68 | color: #060; } 69 | 70 | .kwd { 71 | color: #006; 72 | font-weight: bold; } 73 | 74 | .com { 75 | color: #600; 76 | font-style: italic; } 77 | 78 | .typ { 79 | color: #404; 80 | font-weight: bold; } 81 | 82 | .lit { 83 | color: #044; } 84 | 85 | .pun, .opn, .clo { 86 | color: #440; } 87 | 88 | .tag { 89 | color: #006; 90 | font-weight: bold; } 91 | 92 | .atn { 93 | color: #404; } 94 | 95 | .atv { 96 | color: #060; } } 97 | /* Style */ 98 | /* 99 | pre.prettyprint { 100 | background: white; 101 | font-family: Consolas, Monaco, 'Andale Mono', monospace; 102 | font-size: 12px; 103 | line-height: 1.5; 104 | border: 1px solid #ccc; 105 | padding: 10px; } 106 | */ 107 | 108 | /* Specify class=linenums on a pre to get line numbering */ 109 | ol.linenums { 110 | margin-top: 0; 111 | margin-bottom: 0; } 112 | 113 | /* IE indents via margin-left */ 114 | li.L0, 115 | li.L1, 116 | li.L2, 117 | li.L3, 118 | li.L4, 119 | li.L5, 120 | li.L6, 121 | li.L7, 122 | li.L8, 123 | li.L9 { 124 | /* */ } 125 | 126 | /* Alternate shading for lines */ 127 | li.L1, 128 | li.L3, 129 | li.L5, 130 | li.L7, 131 | li.L9 { 132 | /* */ } 133 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mark-dom", 3 | "version": "0.0.3", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "dependencies": { 7 | "lodash": "^4.17.4", 8 | "markdown-table": "^1.1.1", 9 | "matcher": "^1.0.0", 10 | "remark": "^7.0.1", 11 | "remark-stringify": "^3.0.1" 12 | }, 13 | "devDependencies": { 14 | "babel-core": "^6.23.1", 15 | "babel-jest": "^19.0.0", 16 | "babel-preset-es2015": "^6.22.0", 17 | "coveralls": "^2.13.1", 18 | "eslint": "^4.3.0", 19 | "eslint-plugin-fp": "^2.3.0", 20 | "eslint-plugin-import": "^2.7.0", 21 | "eslint-plugin-prettier": "^2.1.2", 22 | "eslint-plugin-unicorn": "^2.1.2", 23 | "jest": "^20.0.4", 24 | "minami": "^1.2.3", 25 | "prettier": "^1.5.3" 26 | }, 27 | "scripts": { 28 | "docs": "rm -r docs; jsdoc src/*.js -t ./node_modules/minami/ -d docs -R README.md", 29 | "lint": "eslint src", 30 | "test": "jest", 31 | "test-watch": "jest --watch" 32 | }, 33 | "jest": { 34 | "collectCoverage": true, 35 | "coverageDirectory": "/coverage", 36 | "coveragePathIgnorePatterns": [ 37 | "/node_modules/" 38 | ], 39 | "coverageReporters": [ 40 | "text", 41 | "lcov" 42 | ] 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/__test__/error.test.js: -------------------------------------------------------------------------------- 1 | const error = require("../error"); 2 | 3 | const isError = err => Error.prototype.isPrototypeOf(err); 4 | 5 | describe("error", () => { 6 | test("it has badMarkdownSrc error", () => { 7 | expect(error.badMarkdownSrc).toBeDefined(); 8 | }); 9 | 10 | test("badMarkdownSrc can return a new Error", () => { 11 | expect(isError(error.badMarkdownSrc())).toBe(true); 12 | }); 13 | 14 | test("it has doesNotExist error", () => { 15 | expect(error.doesNotExist).toBeDefined(); 16 | }); 17 | 18 | test("doesNotExist can return a new Error", () => { 19 | expect(isError(error.doesNotExist())).toBe(true); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /src/__test__/get.test.js: -------------------------------------------------------------------------------- 1 | const { 2 | base, 3 | firstHeader, 4 | exampleMarkdown, 5 | strip 6 | } = require("./testHelper.js"); 7 | 8 | // Get 9 | describe("get function", () => { 10 | test("it has a get function", () => { 11 | expect(base.get).toBeDefined(); 12 | }); 13 | 14 | test("it can return text", () => { 15 | // We expect the string to change a bit spacing, but the content should be the same 16 | // So we'll compare the stripped spacing to stripped spacing. 17 | const expected = strip(base.get()); 18 | const actual = strip(exampleMarkdown); 19 | expect(expected).toBe(actual); 20 | }); 21 | 22 | test("it can return text after getting a node", () => { 23 | const actual = strip(base.heading().get()); 24 | const expected = strip(firstHeader); 25 | expect(actual).toBe(expected); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /src/__test__/getAll.test.js: -------------------------------------------------------------------------------- 1 | const markdown = require("../index.js"); 2 | const { base, exampleMarkdown, strip } = require("./testHelper.js"); 3 | 4 | describe("getAll function", () => { 5 | test("it has a getAll function", () => { 6 | expect(base.getAll).toBeDefined(); 7 | }); 8 | 9 | test("it can return text", () => { 10 | // We expect the string to change a bit spacing, but the content should be the same 11 | // So we'll compare the stripped spacing to stripped spacing. 12 | const actual = strip(base.getAll()); 13 | const expected = strip(exampleMarkdown); 14 | expect(actual).toBe(expected); 15 | }); 16 | 17 | test("it can return ALL the text after getting a node", () => { 18 | const str = `# Hey there Folks 19 | I'm mr foops 20 | `; 21 | const actual = strip(markdown(str).heading().getAll()); 22 | const expected = strip(str); 23 | expect(actual).toBe(expected); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/__test__/heading.test.js: -------------------------------------------------------------------------------- 1 | const MarkdownNode = require("../markdown.js"); 2 | const mrk = require("../index.js"); 3 | 4 | const { base } = require("./testHelper.js"); 5 | 6 | const specificHeadersMarkdownStr = ` 7 | # First 8 | some text here. 9 | 10 | # Second 11 | `; // Note this formatting is important 12 | 13 | // Heading 14 | describe("heading function", () => { 15 | test("it has a heading function", () => { 16 | expect(base.heading).toBeDefined(); 17 | }); 18 | 19 | test("it can return a MarkdownNode", () => { 20 | const heading = base.heading(); 21 | expect(MarkdownNode.prototype.isPrototypeOf(heading)).toBe(true); 22 | }); 23 | 24 | test("it will throw an error if it can't find something", () => { 25 | expect(() => mrk(" ").heading()).toThrow(); 26 | }); 27 | 28 | test("it can find a heading type", () => { 29 | expect(base.heading().type()).toBe("heading"); 30 | }); 31 | 32 | test("it can find a child heading", () => { 33 | expect(base.heading().heading().type()).toBe("heading"); 34 | }); 35 | 36 | test("it can return a child's child heading's text", () => { 37 | const str = ` 38 | # Hello 39 | ## Subheader 40 | `; 41 | expect(mrk(str).heading("## *").get()).toBe("## Subheader"); 42 | }); 43 | 44 | test("it can find the first header", () => { 45 | const mrkNode = mrk(specificHeadersMarkdownStr); 46 | 47 | expect(mrkNode.heading().value()).toBe("First"); 48 | }); 49 | 50 | test("it can find a specific header", () => { 51 | const mrkNode = mrk(specificHeadersMarkdownStr); 52 | 53 | expect(mrkNode.heading("Second").value()).toBe("Second"); 54 | }); 55 | 56 | test("it can find a header via glob syntax", () => { 57 | const mrkNode = mrk(specificHeadersMarkdownStr); 58 | 59 | expect(mrkNode.heading("Se*").value()).toBe("Second"); 60 | }); 61 | }); 62 | -------------------------------------------------------------------------------- /src/__test__/index.test.js: -------------------------------------------------------------------------------- 1 | const mrk = require("../index.js"); 2 | 3 | test("mrk can throw an error when passed a function", () => { 4 | const func = () => {}; 5 | expect(() => { 6 | mrk(func); 7 | }).toThrow(); 8 | }); 9 | 10 | test("mrk can get some basic markdown", () => { 11 | expect(mrk("# Hello").get()).toBe("# Hello"); 12 | }); 13 | 14 | test("mrk can take nothing", () => { 15 | expect(mrk().type()).toBe("root"); 16 | }); 17 | -------------------------------------------------------------------------------- /src/__test__/paragraph.test.js: -------------------------------------------------------------------------------- 1 | const MarkdownNode = require("../markdown.js"); 2 | const markdown = require("../index.js"); 3 | 4 | const { base } = require("./testHelper.js"); 5 | 6 | const specificParagraphMarkdownStr = ` 7 | # First 8 | firstParagraph 9 | 10 | # Second 11 | secondParagraph 12 | `; // Note this formatting is important 13 | 14 | // Paragraph 15 | describe("paragraph function", () => { 16 | test("it has a paragraph function", () => { 17 | expect(base.paragraph).toBeDefined(); 18 | }); 19 | 20 | test("it can return a MarkdownNode", () => { 21 | const paragraph = base.paragraph(); 22 | expect(MarkdownNode.prototype.isPrototypeOf(paragraph)).toBe(true); 23 | }); 24 | 25 | test("it will throw an error if it can't find something", () => { 26 | expect(() => markdown(" ").paragraph()).toThrow(); 27 | }); 28 | 29 | test("it can find a paragraph type", () => { 30 | expect(base.paragraph().type()).toBe("paragraph"); 31 | }); 32 | 33 | test("it can find a paragraph inside of a heading", () => { 34 | expect(base.heading().paragraph().type()).toBe("paragraph"); 35 | }); 36 | 37 | test("it can find a specific paragraph", () => { 38 | const mrk = markdown(specificParagraphMarkdownStr); 39 | expect(mrk.paragraph("secondParagraph").value()).toBe("secondParagraph"); 40 | }); 41 | 42 | test("it can find a specific paragraph inside of a heading", () => { 43 | const mrk = markdown(specificParagraphMarkdownStr); 44 | expect(mrk.heading("First").paragraph("firstParagraph").value()).toBe( 45 | "firstParagraph" 46 | ); 47 | }); 48 | 49 | test("it will error if it can't find a specific item", () => { 50 | const mrk = markdown(specificParagraphMarkdownStr); 51 | expect(() => { 52 | mrk.paragraph("I DONT EXIST").value(); 53 | }).toThrow(); 54 | }); 55 | 56 | test("it can find a header via glob syntax", () => { 57 | const mrk = markdown(specificParagraphMarkdownStr); 58 | 59 | expect(mrk.paragraph("Se*").value()).toBe("secondParagraph"); 60 | }); 61 | }); 62 | -------------------------------------------------------------------------------- /src/__test__/set.test.js: -------------------------------------------------------------------------------- 1 | const { base, strip } = require("./testHelper.js"); 2 | const mrk = require("../index.js"); 3 | 4 | // Set 5 | describe("set function", () => { 6 | test("it has a set function", () => { 7 | expect(base.set).toBeDefined(); 8 | }); 9 | 10 | test("it can set a header", () => { 11 | const title = "yes, hello, I am title"; 12 | expect(base.heading().set(title).value()).toBe(title); 13 | }); 14 | 15 | test("it can set something after recieving nothing", () => { 16 | expect(mrk().set("Hey").getAll()).toBe("Hey"); 17 | }); 18 | 19 | test("it can override something", () => { 20 | expect(mrk().set("first").paragraph().set("second").getAll()).toBe( 21 | "second" 22 | ); 23 | }); 24 | 25 | test("it has a setTable function", () => { 26 | expect(mrk().setTable).toBeDefined(); 27 | }); 28 | 29 | test("it can make tables", () => { 30 | const table = [["one", "two"], ["a", "b"]]; 31 | const expectedTable = strip(` 32 | | one | two | 33 | |---|---| 34 | | a | b | 35 | `); 36 | const actual = strip(mrk().setTable(table).getAll()); 37 | 38 | expect(actual).toBe(expectedTable); 39 | }); 40 | }); 41 | -------------------------------------------------------------------------------- /src/__test__/testHelper.js: -------------------------------------------------------------------------------- 1 | const markdown = require("../index.js"); 2 | 3 | // Helpers 4 | const firstHeaderValue = `Hey There`; 5 | const firstHeader = `# ${firstHeaderValue}`; 6 | const exampleMarkdown = `${firstHeader} 7 | how you doing. 8 | ## Whats up 9 | `; 10 | const base = markdown(exampleMarkdown); 11 | 12 | function strip(str) { 13 | return str.replace(/\s/g, ""); 14 | } 15 | 16 | export { strip, exampleMarkdown, firstHeaderValue, firstHeader, base }; 17 | -------------------------------------------------------------------------------- /src/__test__/type.test.js: -------------------------------------------------------------------------------- 1 | const mrk = require("../index.js"); 2 | const { base } = require("./testHelper.js"); 3 | const { types } = require("../constants.js"); 4 | 5 | // Type 6 | describe("type function", () => { 7 | test("it has a type function", () => { 8 | expect(base.type).toBeDefined(); 9 | }); 10 | 11 | test("it can get a root", () => { 12 | expect(base.type()).toBe(types.ROOT); 13 | }); 14 | 15 | test("it can get a heading", () => { 16 | expect(base.heading().type()).toBe(types.HEADING); 17 | }); 18 | 19 | test("it can get a paragraph", () => { 20 | expect(base.paragraph().type()).toBe(types.PARAGRAPH); 21 | }); 22 | 23 | test("it can get paragraph on a regular string", () => { 24 | expect(mrk("hi im a paragraph").paragraph().type()).toBe(types.PARAGRAPH); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /src/__test__/value.test.js: -------------------------------------------------------------------------------- 1 | const { base, firstHeaderValue } = require("./testHelper.js"); 2 | 3 | // Value 4 | describe("value function", () => { 5 | test("it has a value function", () => { 6 | expect(base.value).toBeDefined(); 7 | }); 8 | 9 | test("it can get a value of a heading", () => { 10 | expect(base.heading().value()).toBe(firstHeaderValue); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /src/constants.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | types: { 3 | ROOT: "root", 4 | HEADING: "heading", 5 | PARAGRAPH: "paragraph", 6 | TABLE: "table" 7 | } 8 | }; 9 | -------------------------------------------------------------------------------- /src/error.js: -------------------------------------------------------------------------------- 1 | // Messages 2 | const BAD_MARKDOWN_SRC_TYPE_MESSAGE = `Mark-dom requires either a string or an AST object as the parameter.`; 3 | const doesNotExistMessage = type => `Mark-dom can't find this ${type}.`; 4 | 5 | module.exports = { 6 | badMarkdownSrc: () => new Error(BAD_MARKDOWN_SRC_TYPE_MESSAGE), 7 | doesNotExist: type => new Error(doesNotExistMessage(type)) 8 | }; 9 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | const MarkdownNode = require("./markdown.js"); 2 | 3 | module.exports = function markdown(src) { 4 | return new MarkdownNode(src); 5 | }; 6 | -------------------------------------------------------------------------------- /src/markdown.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Defines a MarkdownNode, the main abstraction for the Markdown AST. 3 | */ 4 | const makeTable = require("markdown-table"); 5 | const remark = require("remark"); 6 | const stringify = require("remark-stringify"); 7 | const _ = require("lodash"); 8 | const error = require("./error.js"); 9 | const { types } = require("./constants.js"); 10 | const query = require("./query"); 11 | 12 | /** 13 | * Helpers 14 | */ 15 | 16 | /** 17 | * @private 18 | */ 19 | function throwIfNotExist(component, type) { 20 | if (!component) throw error.doesNotExist(type); 21 | } 22 | 23 | /** 24 | * A MarkdownNode is an object describing a node in the 25 | * Abstract Syntax Tree (AST) of the markdown. 26 | * 27 | * @example 28 | * import mrk = require("mark-dom"); 29 | * mrk("# Hello").get(); // Will return "# Hello" 30 | * 31 | */ 32 | class MarkdownNode { 33 | /** 34 | * A markdown node takes either an Abstract Syntax Tree (AST) 35 | * or a markdown string. 36 | * 37 | * @param {ast|string} src The markdown string that we'll parse into an AST. 38 | * @param {JSON} [options] Options to be passed into MarkdownNode 39 | */ 40 | constructor(src, options) { 41 | if (typeof src === "object") { 42 | this._ast = options._ast; 43 | this._pointer = src; 44 | } else if (typeof src === "string") { 45 | this._ast = remark().parse(src); 46 | this._pointer = this._ast; 47 | } else if (typeof src === "undefined") { 48 | this._ast = remark().parse(""); // treat undefined like an empty string. 49 | this._pointer = this._ast; 50 | } else { 51 | throw error.badMarkdownSrc(); 52 | } 53 | } 54 | 55 | /** 56 | * Returns the markdown string version of the node you're currently on. 57 | * 58 | * @example 59 | * // Returns "## Subheader" 60 | * mrk(` 61 | * # Hello 62 | * ## Subheader 63 | * `).heading("## *").get(); 64 | * 65 | * @return {String} The String version of the CURRENT node we're on. 66 | */ 67 | get() { 68 | return remark().use(stringify).stringify(this._pointer).trim(); 69 | } 70 | 71 | /** 72 | * Returns the markdown string version of the entire AST of this piece of 73 | * markdown. 74 | * @return {String} The String version of the ENTIRE compiled Markdown AST. 75 | */ 76 | getAll() { 77 | return remark().use(stringify).stringify(this._ast).trim(); 78 | } 79 | 80 | /** 81 | * Gets a new MarkdownNode representing an aribtary AST type. 82 | * 83 | * @example 84 | * // Returns "# Hello" 85 | * mrk().set("# Hello").search("# H*").getAll(); 86 | * 87 | * @param {String} 88 | * @param {String} [searchWord] A string to search for in the node. Can use wildcard * syntax. 89 | */ 90 | search(type, searchWord) { 91 | const node = searchWord 92 | ? query.where(this._ast, type, searchWord) 93 | : query.first(this._ast, type); 94 | 95 | throwIfNotExist(node, type); 96 | return new MarkdownNode(node, { _ast: this._ast }); 97 | } 98 | 99 | /** 100 | * Gets a new MarkdownNode representing the first heading it finds. 101 | * 102 | * @example 103 | * // Returns a MarkdownNode at the heading. 104 | * mrk("# Hello").heading("H*"); 105 | * 106 | * @example 107 | * // Returns a MarkdownNode representing "# First" 108 | * mrk(` 109 | * # First 110 | * some text 111 | * 112 | * # Second 113 | * other text 114 | * `).heading(); 115 | * 116 | * @param {String} [searchWord] A string to search for in the heading. Can use wildcard * syntax. 117 | * @return {MarkdownNode} A new child node at the next heading. 118 | */ 119 | heading(searchWord) { 120 | return this.search(types.HEADING, searchWord); 121 | } 122 | 123 | /** 124 | * Gets a new MarkdownNode representing the first paragraph it finds. 125 | * 126 | * @example 127 | * // Returns a MarkdownNode at the paragraph. 128 | * mrk("Hello").paragraph("H*"); 129 | * 130 | * @example 131 | * // Returns a MarkdownNode representing "First Paragraph" 132 | * mrk(` 133 | * # First 134 | * First Paragraph 135 | * 136 | * # Second 137 | * Second Paragraph 138 | * `).paragraph(); 139 | * 140 | * @param {String} [searchWord] A string to search for in the paragraph. Can use wildcard * syntax. 141 | * @return {MarkdownNode} 142 | */ 143 | paragraph(searchWord) { 144 | return this.search(types.PARAGRAPH, searchWord); 145 | } 146 | 147 | /** 148 | * Gets a new MarkdownNode representing the first paragraph it finds 149 | * 150 | * 151 | * @param {String} [searchWord] A string to search for somewhere in the table. Can use wildcard * syntax. 152 | * @return {MarkdownNode} 153 | */ 154 | table(searchWord) { 155 | return this.search(types.TABLE, searchWord); 156 | } 157 | 158 | /** 159 | * Create a markdown table from an array. 160 | * @param {Array} array 161 | * @return {MarkdownNode} 162 | */ 163 | setTable(array) { 164 | const tableAST = remark().parse(makeTable(array)); 165 | const wrappedTable = new MarkdownNode(remark().parse(array), { 166 | _ast: tableAST 167 | }); 168 | 169 | this._pointer.children = []; // THIS IS PRETTY BAD. 170 | this._pointer.children.push(wrappedTable.table()._pointer); // TODO: HMMM THIS SEEMS FISHY. PROBABLY SHOULD CLEAR SOME STUFF FIRST 171 | 172 | return new MarkdownNode(this._pointer, { _ast: this._ast }); 173 | } 174 | 175 | /** 176 | * Sets the current node's value to the str input 177 | * @param {String} str 178 | * @return {MarkdownNode} 179 | */ 180 | set(str) { 181 | // In the case that this node is empty, create something new! 182 | if (_.isEmpty(this._pointer.children)) { 183 | this._pointer = this._ast = remark().parse(str); 184 | return new MarkdownNode(this._pointer, { _ast: this._ast }); 185 | } 186 | 187 | this._pointer.children[0].value = str; // TODO: This is probably going to have some weird effects. 188 | return new MarkdownNode(this._pointer, { _ast: this._ast }); 189 | } 190 | 191 | /** 192 | * Returns the type of the node you're currently on. 193 | * 194 | * @example 195 | * mrk("# Hello").heading().type(); // Returns "heading" 196 | * 197 | * @example 198 | * mark("Im a paragraph").paragraph().type(); // Returns "paragraph" 199 | * 200 | * @example 201 | * mrk("hello").type(); // Returns "root" 202 | * 203 | * @return {String} the type of node you're currently on. 204 | */ 205 | type() { 206 | return this._pointer.type; 207 | } 208 | 209 | /** 210 | * Returns the value of the node you're on. 211 | * If get() returns the markdown string of where you're at, this 212 | * returns the actual value of where you're at. 213 | * 214 | * @example 215 | * mrk("# Hello I am header").value(); // Returns "Hello I am header" 216 | * 217 | * @example 218 | * var m = mrk("# Hello I am header"); 219 | * const isTrue = m.get() != m.value(); // True 220 | * 221 | * @return {String} The string value of the node you're on. 222 | */ 223 | value() { 224 | return this._pointer.children[0].value; // this is probably gonna have some weird effects. 225 | } 226 | } 227 | 228 | module.exports = MarkdownNode; 229 | -------------------------------------------------------------------------------- /src/query/__test__/query.test.js: -------------------------------------------------------------------------------- 1 | const query = require("../index.js"); 2 | const remark = require("remark"); 3 | const { types } = require("../../constants"); 4 | 5 | const someMarkdown = ` 6 | # First 7 | Some text 8 | # Second 9 | `; 10 | 11 | const ast = remark.parse(someMarkdown); 12 | 13 | describe("query", () => { 14 | test("it has a function called first", () => { 15 | expect(query.first); 16 | }); 17 | 18 | test("it can find the first of a type", () => { 19 | expect(query.first(ast, types.HEADING).children[0].value).toBe("First"); 20 | }); 21 | 22 | test("it can handle not finding something in first", () => { 23 | expect(query.first(ast, "NOT A TYPE")).toBe(undefined); 24 | }); 25 | 26 | test("it has a function called where", () => { 27 | expect(query.where).toBeDefined(); 28 | }); 29 | 30 | test("it can find an item in an ast", () => { 31 | expect(query.where(ast, types.HEADING, "Second").children[0].value).toBe( 32 | "Second" 33 | ); 34 | }); 35 | 36 | test("it can handle not finding something in where", () => { 37 | expect(query.where(ast, types.HEADING, "Not a header")).toBe(undefined); 38 | }); 39 | }); 40 | -------------------------------------------------------------------------------- /src/query/__test__/util.test.js: -------------------------------------------------------------------------------- 1 | const { valuesMatch, allButHashes } = require("../util.js"); 2 | 3 | describe("valuesMatch", () => { 4 | test("it can match exact strings", () => { 5 | expect(valuesMatch("hey", "hey")).toBe(true); 6 | }); 7 | 8 | test("it can match values with spaces", () => { 9 | expect(valuesMatch("hey ", "hey ")).toBe(true); 10 | }); 11 | 12 | test("it can match glob values", () => { 13 | expect(valuesMatch("cats and dogs", "cats and *")).toBe(true); 14 | }); 15 | }); 16 | 17 | describe("allButHashes", () => { 18 | test("it returns original string if no hashes", () => { 19 | expect(allButHashes("Nohashes")).toBe("Nohashes"); 20 | }); 21 | 22 | test("It returns no hashes from a hashed string", () => { 23 | expect(allButHashes("## hashes")).toBe("hashes"); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/query/index.js: -------------------------------------------------------------------------------- 1 | const { hasValue } = require("./util.js"); 2 | 3 | /** 4 | * Search through the ast for a node that matches the `type` and has a child with the `value`. 5 | * @param {Object} ast 6 | * @param {String} type 7 | * @param {String} query 8 | */ 9 | function where(ast, type, query) { 10 | const childrenOfType = ast.children.filter(d => d.type === type); 11 | const childrenThatMatchQuery = childrenOfType.filter(d => hasValue(d, query)); 12 | return childrenThatMatchQuery[0]; // For not only take the first one 13 | } 14 | 15 | /** 16 | * Grabs the first item of a type 17 | * @param {Object} ast 18 | * @param {String} type 19 | */ 20 | function first(ast, type) { 21 | const childrenOfType = ast.children.filter(d => d.type === type); 22 | return childrenOfType[0]; 23 | } 24 | 25 | module.exports = { 26 | where, 27 | first 28 | }; 29 | -------------------------------------------------------------------------------- /src/query/util.js: -------------------------------------------------------------------------------- 1 | const _ = require("lodash"); 2 | const matcher = require("matcher"); 3 | const remark = require("remark"); 4 | const stringify = require("remark-stringify"); 5 | 6 | /** 7 | * @param {String} str 8 | * @return {String} The first segment, if a string is split by spaces. 9 | */ 10 | function firstSegment(str) { 11 | return str.split(" ")[0]; 12 | } 13 | 14 | /** 15 | * Tests if the list starts with hashes 16 | * 17 | * @example 18 | * startsWithHashes("## Hello yes I am hashes"); // true 19 | * startsWithHashes("I am not hashbrowns."); // false 20 | * startsWithHashes("##NOTICE_I_HAVE_NO_SPACES"); // false (no space between ## and string) 21 | * 22 | * @param {String} test 23 | * @return {Boolean} true if starts with hashes 24 | */ 25 | function startsWithHashes(test) { 26 | const first = firstSegment(test); 27 | return Array.from(first).every(x => x === "#"); // All characters are hashes 28 | } 29 | 30 | /** 31 | * Returns the string but without any hashes in front of it. 32 | * 33 | * @example 34 | * allButHashes("## Hello") // returns "Hello" 35 | * 36 | * @param {String} str 37 | * @return {String} 38 | */ 39 | function allButHashes(str) { 40 | if (!startsWithHashes(str)) return str; 41 | const segments = str.split(" "); 42 | return segments.splice(1, segments.length).join(); 43 | } 44 | 45 | /** 46 | * Matches via glob matching 47 | * @param {String} test the item to test against 48 | * @param {String} pattern the glob pattern we're looking for 49 | */ 50 | function valuesMatch(test, pattern) { 51 | // If we're looking for a header, check that the header length matches. 52 | if (startsWithHashes(pattern)) { 53 | if (firstSegment(test) !== firstSegment(pattern)) return false; 54 | test = allButHashes(test); 55 | pattern = allButHashes(pattern); 56 | } 57 | 58 | return matcher.isMatch(test, pattern); 59 | } 60 | 61 | /** 62 | * Returns true if and child of the node contains the query 63 | * @param {Object} node 64 | * @param {String} query 65 | */ 66 | function hasValue(node, query) { 67 | const value = remark().use(stringify).stringify(node).trim(); 68 | if (valuesMatch(value, query)) return true; // We found it! 69 | if (_.isEmpty(node.children)) return false; // We hit a dead end :( 70 | 71 | // Search through every child! 72 | const searches = node.children.map(c => hasValue(c, query)); 73 | 74 | return _.some(searches); // if any work, return true! 75 | } 76 | 77 | module.exports = { 78 | valuesMatch, 79 | hasValue, 80 | allButHashes 81 | }; 82 | --------------------------------------------------------------------------------