├── .eslintignore ├── .github ├── dependabot.yml └── workflows │ ├── on-dependabot.yml │ ├── on-push.yml │ └── on-release.yml ├── .gitignore ├── .npmignore ├── .prettierignore ├── .yarn ├── plugins │ └── @yarnpkg │ │ └── plugin-interactive-tools.cjs └── releases │ └── yarn-2.3.3.cjs ├── .yarnrc.yml ├── CHANGELOG.md ├── README.md ├── media └── cover.png ├── package.json ├── src ├── highlight.js └── index.js ├── test ├── fixtures │ ├── all.md │ ├── autolinker.md │ ├── command-line.md │ ├── data-uri-highlight.md │ ├── diff-highlight.md │ ├── inline-color.md │ ├── keep-markup.md │ ├── languages.md │ ├── legend.md │ ├── line-highlight.md │ ├── line-numbers.md │ ├── no-lang.md │ ├── show-invisibles.md │ └── treeview.md ├── index.js ├── outputs │ ├── all.hast.html │ ├── all.hast.png │ ├── all.jsx.html │ ├── all.jsx.png │ ├── all.mdast.html │ ├── all.mdast.png │ ├── autolinker.hast.html │ ├── autolinker.hast.png │ ├── autolinker.jsx.html │ ├── autolinker.jsx.png │ ├── autolinker.mdast.html │ ├── autolinker.mdast.png │ ├── command-line.hast.html │ ├── command-line.hast.png │ ├── command-line.jsx.html │ ├── command-line.jsx.png │ ├── command-line.mdast.html │ ├── command-line.mdast.png │ ├── data-uri-highlight.hast.html │ ├── data-uri-highlight.hast.png │ ├── data-uri-highlight.jsx.html │ ├── data-uri-highlight.jsx.png │ ├── data-uri-highlight.mdast.html │ ├── data-uri-highlight.mdast.png │ ├── diff-highlight.hast.html │ ├── diff-highlight.hast.png │ ├── diff-highlight.jsx.html │ ├── diff-highlight.jsx.png │ ├── diff-highlight.mdast.html │ ├── diff-highlight.mdast.png │ ├── inline-color.hast.html │ ├── inline-color.hast.png │ ├── inline-color.jsx.html │ ├── inline-color.jsx.png │ ├── inline-color.mdast.html │ ├── inline-color.mdast.png │ ├── keep-markup.hast.html │ ├── keep-markup.hast.png │ ├── keep-markup.jsx.html │ ├── keep-markup.jsx.png │ ├── keep-markup.mdast.html │ ├── keep-markup.mdast.png │ ├── languages.hast.html │ ├── languages.hast.png │ ├── languages.jsx.html │ ├── languages.jsx.png │ ├── languages.mdast.html │ ├── languages.mdast.png │ ├── legend.hast.html │ ├── legend.hast.png │ ├── legend.jsx.html │ ├── legend.jsx.png │ ├── legend.mdast.html │ ├── legend.mdast.png │ ├── line-highlight.hast.html │ ├── line-highlight.hast.png │ ├── line-highlight.jsx.html │ ├── line-highlight.jsx.png │ ├── line-highlight.mdast.html │ ├── line-highlight.mdast.png │ ├── line-numbers.hast.html │ ├── line-numbers.hast.png │ ├── line-numbers.jsx.html │ ├── line-numbers.jsx.png │ ├── line-numbers.mdast.html │ ├── line-numbers.mdast.png │ ├── no-lang.hast.html │ ├── no-lang.hast.png │ ├── no-lang.jsx.html │ ├── no-lang.jsx.png │ ├── no-lang.mdast.html │ ├── no-lang.mdast.png │ ├── show-invisibles.hast.html │ ├── show-invisibles.hast.png │ ├── show-invisibles.jsx.html │ ├── show-invisibles.jsx.png │ ├── show-invisibles.mdast.html │ ├── show-invisibles.mdast.png │ ├── theme.css │ ├── treeview.hast.html │ ├── treeview.hast.png │ ├── treeview.jsx.html │ ├── treeview.jsx.png │ ├── treeview.mdast.html │ └── treeview.mdast.png └── snapshots │ ├── index.js.md │ └── index.js.snap └── yarn.lock /.eslintignore: -------------------------------------------------------------------------------- 1 | dist 2 | build 3 | .build 4 | logfile 5 | .nyc_output 6 | coverage 7 | node_modules 8 | 9 | .git/* 10 | .DS_Store 11 | .npmrc 12 | .yarnclean 13 | .eslintignore 14 | .prettierignore 15 | .upignore 16 | .npmignore 17 | .gitignore 18 | .dockerignore 19 | .yarnrc 20 | .haxt 21 | .flowconfig 22 | .firebaserc 23 | .graphqlconfig 24 | .editorconfig 25 | .next 26 | _next 27 | 28 | license 29 | yarn.lock 30 | Dockerfile.* 31 | Dockerfile 32 | 33 | _env*ac 34 | .env.* 35 | *.env 36 | *.ico 37 | *.html 38 | *.xml 39 | *.log 40 | *.svg 41 | *.map 42 | *.png 43 | *.snap 44 | *.txt 45 | *.sketch 46 | *.ttf 47 | *.eot 48 | *.ttf 49 | *.woff 50 | *.woff2 51 | *.out 52 | *.dms 53 | *.sh 54 | *.tar.gz 55 | *.pem 56 | *.jpg 57 | *.gif 58 | *.graphcool 59 | *.re 60 | *.wasm 61 | *.yml 62 | *.toml 63 | *.jar 64 | *.zip -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 2 | version: 2 3 | updates: 4 | - package-ecosystem: "github-actions" 5 | directory: "/" 6 | schedule: 7 | interval: "daily" 8 | 9 | - package-ecosystem: 'npm' 10 | directory: '/' 11 | schedule: 12 | interval: 'daily' 13 | commit-message: 14 | prefix: 'chore' 15 | include: 'scope' 16 | versioning-strategy: increase-if-necessary 17 | -------------------------------------------------------------------------------- /.github/workflows/on-dependabot.yml: -------------------------------------------------------------------------------- 1 | name: Continuous Updates 2 | 3 | on: 4 | push: 5 | branches: [ dependabot/npm_and_yarn/** ] 6 | pull_request: 7 | types: [opened, synchronize, reopened] 8 | branches: [ dependabot/npm_and_yarn/** ] 9 | 10 | jobs: 11 | update-manifests: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: technote-space/auto-cancel-redundant-job@v1 15 | - uses: actions/checkout@v2 16 | with: 17 | fetch-depth: 20 18 | persist-credentials: false 19 | - name: Setup Node.js 20 | uses: actions/setup-node@v2.1.5 21 | with: 22 | node-version: '14.x' 23 | - name: Config Git 24 | run: | 25 | git config --global user.name '${{ github.event.commits[0].author.name }}' 26 | git config --global user.email '${{ github.event.commits[0].author.email }}' 27 | - name: Fix yarn.lock 28 | run: | 29 | # get current branch 30 | echo ::set-env name=GITHUB_REF_SLUG::"$(git branch --show-current)" 31 | # revert changes to yarn.lock 32 | git checkout ${{ github.sha }}^ -- yarn.lock 33 | # IF only yarn.lock changed, update package.json too 34 | git diff --name-only HEAD^ HEAD | grep -q 'package.json' || yarn up `git log -1 --pretty=%s | awk '{ print $3 }'` 35 | # regardless, run yarn to update yarn.lock 36 | yarn 37 | # stage package.json and yarn.lock 38 | git add yarn.lock package.json 39 | # commit changes 40 | git commit --amend --no-edit --allow-empty -n 41 | env: 42 | YARN_CHECKSUM_BEHAVIOR: update 43 | YARN_ENABLE_SCRIPTS: 0 44 | - name: Test 45 | run: yarn run test 46 | - name: Push changes 47 | uses: ad-m/github-push-action@v0.6.0 48 | with: 49 | github_token: ${{ secrets.GITHUB_TOKEN }} 50 | branch: ${{ env.GITHUB_REF_SLUG }} 51 | force: true 52 | -------------------------------------------------------------------------------- /.github/workflows/on-push.yml: -------------------------------------------------------------------------------- 1 | name: Continuous Integration 2 | 3 | on: push 4 | 5 | jobs: 6 | setup: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: technote-space/auto-cancel-redundant-job@v1 10 | - name: Checkout 11 | uses: actions/checkout@v2 12 | - name: Setup Node.js 13 | uses: actions/setup-node@v2.1.5 14 | with: 15 | node-version: '13.x' 16 | - name: Setup Cache 17 | uses: actions/cache@v2.1.5 18 | with: 19 | path: .yarn 20 | key: ${{ runner.os }}-node-modules-${{ hashFiles('yarn.lock') }} 21 | - name: Install dependencies 22 | run: yarn install --immutable 23 | env: 24 | YARN_CHECKSUM_BEHAVIOR: update 25 | 26 | ############################################################################### 27 | # COMMITLINT # 28 | ############################################################################### 29 | commitlint: 30 | needs: setup 31 | runs-on: ubuntu-latest 32 | steps: 33 | - name: Checkout 34 | uses: actions/checkout@v2 35 | with: 36 | fetch-depth: 0 37 | - name: Commit Lint 38 | uses: wagoid/commitlint-github-action@v3.1.0 39 | env: 40 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 41 | 42 | ############################################################################### 43 | # ESLINT # 44 | ############################################################################### 45 | eslint: 46 | needs: setup 47 | runs-on: ubuntu-latest 48 | steps: 49 | - name: Checkout 50 | uses: actions/checkout@v2 51 | - name: Setup Node.js 52 | uses: actions/setup-node@v2.1.5 53 | with: 54 | node-version: '13.x' 55 | - name: Setup Cache 56 | uses: actions/cache@v2.1.5 57 | with: 58 | path: .yarn 59 | key: ${{ runner.os }}-node-modules-${{ hashFiles('yarn.lock') }} 60 | - name: Install dependencies 61 | run: yarn install --immutable --immutable-cache 62 | - name: ESLint 63 | run: yarn run eslint 64 | 65 | ############################################################################### 66 | # TEST # 67 | ############################################################################### 68 | test: 69 | needs: setup 70 | runs-on: ubuntu-latest 71 | steps: 72 | - name: Checkout 73 | uses: actions/checkout@v2 74 | - name: Setup Node.js 75 | uses: actions/setup-node@v2.1.5 76 | with: 77 | node-version: '13.x' 78 | - name: Setup Cache 79 | uses: actions/cache@v2.1.5 80 | with: 81 | path: .yarn 82 | key: ${{ runner.os }}-node-modules-${{ hashFiles('yarn.lock') }} 83 | - name: Install dependencies 84 | run: yarn install --immutable --immutable-cache 85 | - name: Test 86 | run: yarn run test 87 | 88 | ############################################################################### 89 | # RELEASE # 90 | ############################################################################### 91 | release: 92 | needs: [test, eslint, commitlint] 93 | runs-on: ubuntu-latest 94 | steps: 95 | - name: Checkout 96 | uses: actions/checkout@v2 97 | - name: Get branch 98 | uses: rlespinasse/github-slug-action@3.5.1 99 | - name: Release 100 | uses: ridedott/release-me-action@v3.5.20 101 | if: ${{ env.GITHUB_REF_SLUG == 'master' }} 102 | with: 103 | node-module: true 104 | release-rules: | 105 | [{"scope":"deps-dev","release":false},{"scope":"no-release","release":false},{"release":"patch","type":"build"},{"release":"patch","type":"chore"},{"release":"patch","type":"ci"},{"release":"patch","type":"docs"},{"release":"patch","type":"improvement"},{"release":"patch","type":"refactor"},{"release":"minor","type":"feat"}] 106 | env: 107 | GITHUB_TOKEN: ${{ secrets.RELEASE_GITHUB_TOKEN }} 108 | -------------------------------------------------------------------------------- /.github/workflows/on-release.yml: -------------------------------------------------------------------------------- 1 | name: Continuous Delivery 2 | 3 | on: 4 | release: 5 | types: [published] 6 | 7 | jobs: 8 | publish: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Checkout 12 | uses: actions/checkout@v2 13 | - name: Setup Node.js 14 | uses: actions/setup-node@v2.1.5 15 | with: 16 | node-version: '13.x' 17 | registry-url: https://registry.npmjs.com/ 18 | scope: '@sergioramos' 19 | - name: Install dependencies 20 | run: yarn install --immutable 21 | env: 22 | YARN_CHECKSUM_BEHAVIOR: update 23 | - name: Publish 24 | run: npm publish 25 | env: 26 | NODE_AUTH_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }} 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### Testing ### 2 | /coverage 3 | 4 | ### Production ### 5 | /build 6 | /dist 7 | /.next 8 | 9 | ### Misc ### 10 | .env 11 | 12 | ### Yarn ### 13 | yarn-debug.log* 14 | yarn-error.log* 15 | 16 | ### Bower ### 17 | bower_components 18 | .bower-cache 19 | .bower-registry 20 | .bower-tmp 21 | 22 | ### Git ### 23 | *.orig 24 | 25 | ### macOS ### 26 | *.DS_Store 27 | .AppleDouble 28 | .LSOverride 29 | 30 | # Thumbnails 31 | ._* 32 | # Files that might appear in the root of a volume 33 | .DocumentRevisions-V100 34 | .fseventsd 35 | .Spotlight-V100 36 | .TemporaryItems 37 | .Trashes 38 | .VolumeIcon.icns 39 | .com.apple.timemachine.donotpresent 40 | # Directories potentially created on remote AFP share 41 | .AppleDB 42 | .AppleDesktop 43 | Network Trash Folder 44 | Temporary Items 45 | .apdisk 46 | 47 | 48 | ### Node ### 49 | # Logs 50 | logs 51 | *.log 52 | npm-debug.log* 53 | *.out 54 | 55 | # Runtime data 56 | pids 57 | *.pid 58 | *.seed 59 | *.pid.lock 60 | 61 | # Directory for instrumented libs generated by jscoverage/JSCover 62 | lib-cov 63 | 64 | # Coverage directory used by tools like istanbul 65 | coverage 66 | coverage.html 67 | 68 | # nyc test coverage 69 | .nyc_output 70 | 71 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 72 | .grunt 73 | 74 | # node-waf configuration 75 | .lock-wscript 76 | 77 | # Compiled binary addons (http://nodejs.org/api/addons.html) 78 | build/Release 79 | 80 | # Dependency directories 81 | node_modules 82 | jspm_packages 83 | package-lock.json 84 | 85 | # Optional npm cache directory 86 | .npm 87 | 88 | # Optional eslint cache 89 | .eslintcache 90 | 91 | # Optional REPL history 92 | .node_repl_history 93 | 94 | # Output of 'npm pack' 95 | *.tgz 96 | 97 | 98 | ### SublimeText ### 99 | # cache files for sublime text 100 | *.tmlanguage.cache 101 | *.tmPreferences.cache 102 | *.stTheme.cache 103 | 104 | # workspace files are user-specific 105 | *.sublime-workspace 106 | 107 | # project files should be checked into the repository, unless a significant 108 | # proportion of contributors will probably not be using SublimeText 109 | # *.sublime-project 110 | 111 | # sftp configuration file 112 | sftp-config.json 113 | 114 | # Package control specific files 115 | Package Control.last-run 116 | Package Control.ca-list 117 | Package Control.ca-bundle 118 | Package Control.system-ca-bundle 119 | Package Control.cache/ 120 | Package Control.ca-certs/ 121 | bh_unicode_properties.cache 122 | 123 | # Sublime-github package stores a github token in this file 124 | # https://packagecontrol.io/packages/sublime-github 125 | GitHub.sublime-settings 126 | 127 | 128 | ### Vim ### 129 | # swap 130 | [._]*.s[a-w][a-z] 131 | [._]s[a-w][a-z] 132 | # session 133 | Session.vim 134 | # temporary 135 | .netrwhist 136 | *~ 137 | # auto-generated tag files 138 | tags 139 | 140 | 141 | ### Windows ### 142 | # Windows image file caches 143 | Thumbs.db 144 | ehthumbs.db 145 | 146 | # Folder config file 147 | Desktop.ini 148 | 149 | # Recycle Bin used on file shares 150 | $RECYCLE.BIN/ 151 | 152 | # Windows Installer files 153 | *.cab 154 | *.msi 155 | *.msm 156 | *.msp 157 | 158 | # Windows shortcuts 159 | *.lnk 160 | 161 | ### Application Specific ### 162 | .lighthouseci 163 | .yarn/cache 164 | .yarn/install-state.gz 165 | .yarn/build-state.yml 166 | .yarn/unplugged 167 | .npmrc 168 | .husky 169 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .eslintignore 2 | .github 3 | .prettierignore 4 | .yarn 5 | .yarnrc.yml 6 | media 7 | test 8 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | dist 2 | build 3 | .build 4 | logfile 5 | .nyc_output 6 | coverage 7 | .yarn/* 8 | src/prism/load-languages.js 9 | 10 | .git/* 11 | .DS_Store 12 | .npmrc 13 | .nvmrc 14 | .yarnclean 15 | .eslintignore 16 | .prettierignore 17 | .upignore 18 | .npmignore 19 | .gitignore 20 | .dockerignore 21 | .yarnrc 22 | .haxt 23 | .flowconfig 24 | .firebaserc 25 | .graphqlconfig 26 | .editorconfig 27 | .next 28 | _next 29 | .serverless 30 | .lighthouserc 31 | .gitkeep 32 | 33 | license 34 | yarn.lock 35 | Dockerfile.* 36 | Dockerfile 37 | 38 | _env*ac 39 | .env.* 40 | *.env 41 | *.ico 42 | *.html 43 | *.xml 44 | *.log 45 | *.svg 46 | *.map 47 | *.png 48 | *.snap 49 | *.txt 50 | *.sketch 51 | *.ttf 52 | *.eot 53 | *.ttf 54 | *.woff 55 | *.woff2 56 | *.out 57 | *.dms 58 | *.sh 59 | *.tar.gz 60 | *.pem 61 | *.jpg 62 | *.gif 63 | *.graphcool 64 | *.re 65 | *.wasm 66 | *.yml 67 | *.toml 68 | *.jar 69 | *.zip 70 | *.prisma 71 | *.lock 72 | *.diff 73 | *.hbs 74 | *.pro -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | nodeLinker: node-modules 2 | 3 | plugins: 4 | - path: .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs 5 | spec: "@yarnpkg/plugin-interactive-tools" 6 | 7 | yarnPath: .yarn/releases/yarn-2.3.3.cjs 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # remark-prism 2 | 3 | Syntax highlighter for markdown code blocks using [Prism](https://prismjs.com/) - with support for certain [plugins](https://prismjs.com/plugins/). This allows syntax highlighting without running any client-side code - other than CSS. 4 | 5 |
78 |
79 | console
80 | .
81 | log
82 | (
83 | 'Hello World'
84 | )
85 | ;
86 |
87 |
88 | ...133 | ``` 134 | 135 | ## license 136 | 137 | BSD-3-Clause 138 | -------------------------------------------------------------------------------- /media/cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergioramos/remark-prism/49f1f86d50f376c647214c02cf972ce05b0fc756/media/cover.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "remark-prism", 3 | "version": "1.3.6", 4 | "description": "Syntax highlighter for markdown code blocks - with support for plugins", 5 | "license": "BSD-3-Clause", 6 | "repository": "sergioramos/remark-prism", 7 | "main": "src/index.js", 8 | "keywords": [ 9 | "prismjs", 10 | "markdown", 11 | "remark", 12 | "remarkjs", 13 | "remark-plugin" 14 | ], 15 | "publishConfig": { 16 | "registry": "https://registry.npmjs.com", 17 | "access": "public" 18 | }, 19 | "scripts": { 20 | "eslint": "eslint . --ext .js", 21 | "fmt": "prettier --config package.json --write '**/*'", 22 | "test": "NODE_ENV=test ava --serial" 23 | }, 24 | "dependencies": { 25 | "classnames": "^2.3.1", 26 | "css-selector-parser": "^1.4.1", 27 | "escape-html": "^1.0.3", 28 | "jsdom": "^16.5.3", 29 | "parse-numeric-range": "^1.2.0", 30 | "parse5": "^6.0.1", 31 | "parse5-htmlparser2-tree-adapter": "^6.0.1", 32 | "prismjs": "^1.23.0", 33 | "unist-util-map": "^2.0.1" 34 | }, 35 | "devDependencies": { 36 | "@babel/core": "^7.13.15", 37 | "@babel/preset-react": "^7.13.13", 38 | "@commitlint/cli": "^12.1.1", 39 | "@commitlint/config-conventional": "^12.1.1", 40 | "@mdx-js/mdx": "^2.0.0-next.9", 41 | "@mdx-js/react": "^2.0.0-next.9", 42 | "@rollup/plugin-virtual": "^2.0.3", 43 | "apr-for-each": "^3.0.3", 44 | "apr-parallel": "^3.0.3", 45 | "ava": "^3.15.0", 46 | "eslint": "^7.24.0", 47 | "eslint-config-prettier": "^8.1.0", 48 | "eslint-config-xo-space": "^0.27.0", 49 | "husky": "^6.0.0", 50 | "lint-staged": "^10.5.4", 51 | "mz": "^2.7.0", 52 | "npm-run-all": "^4.1.5", 53 | "prettier": "^2.2.1", 54 | "puppeteer": "^8.0.0", 55 | "react": "^17.0.2", 56 | "react-dom": "^17.0.2", 57 | "rehype-format": "^3.1.0", 58 | "rehype-stringify": "^8.0.0", 59 | "remark-html": "^13.0.1", 60 | "remark-parse": "^9.0.0", 61 | "remark-rehype": "^8.1.0", 62 | "remark-stringify": "^9.0.1", 63 | "rollup": "^2.45.2", 64 | "rollup-plugin-babel": "^4.4.0", 65 | "serve": "^11.3.2", 66 | "to-vfile": "^6.1.0", 67 | "unified": "^9.2.1" 68 | }, 69 | "resolutions": { 70 | "fsevents": "1.2.13" 71 | }, 72 | "husky": { 73 | "hooks": { 74 | "pre-commit": "lint-staged", 75 | "commit-msg": "commitlint -E HUSKY_GIT_PARAMS" 76 | } 77 | }, 78 | "lint-staged": { 79 | "*.js": [ 80 | "eslint --fix", 81 | "prettier --config package.json --write", 82 | "git add" 83 | ], 84 | "*.*": [ 85 | "prettier --config package.json --write", 86 | "git add" 87 | ] 88 | }, 89 | "prettier": { 90 | "bracketSpacing": true, 91 | "jsxBracketSameLine": false, 92 | "printWidth": 80, 93 | "semi": true, 94 | "singleQuote": true, 95 | "tabWidth": 2, 96 | "trailingComma": "all", 97 | "useTabs": false 98 | }, 99 | "eslintConfig": { 100 | "extends": [ 101 | "eslint:recommended", 102 | "xo-space/esnext", 103 | "prettier" 104 | ], 105 | "rules": { 106 | "new-cap": 0, 107 | "camelcase": 0, 108 | "capitalized-comments": 0, 109 | "no-promise-executor-return": 0 110 | } 111 | }, 112 | "commitlint": { 113 | "extends": [ 114 | "@commitlint/config-conventional" 115 | ], 116 | "rules": { 117 | "body-max-line-length": [ 118 | 0 119 | ] 120 | } 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/highlight.js: -------------------------------------------------------------------------------- 1 | const escapeHtml = require('escape-html'); 2 | const { readFileSync } = require('fs'); 3 | const { JSDOM } = require('jsdom'); 4 | const parse5 = require('parse5'); 5 | const htmlparser2Adapter = require('parse5-htmlparser2-tree-adapter'); 6 | const { createContext, runInContext } = require('vm'); 7 | 8 | const components = require('prismjs/components.json'); 9 | const getLoader = require('prismjs/dependencies'); 10 | 11 | const PLUGINS = [ 12 | 'autolinker', 13 | 'command-line', 14 | 'data-uri-highlight', 15 | 'diff-highlight', 16 | 'inline-color', 17 | 'keep-markup', 18 | 'line-numbers', 19 | 'show-invisibles', 20 | 'treeview', 21 | ]; 22 | 23 | const domHighlight = (value, attrs = {}, range = []) => { 24 | const MULTILINE_TOKEN_SPAN = /[^<]*\n[^<]*<\/span>/g; 25 | 26 | // eslint-disable-next-line no-undef 27 | const pre = window.document.createElement('pre'); 28 | // eslint-disable-next-line no-undef 29 | const code = window.document.createElement('code'); 30 | 31 | for (const [key, value] of Object.entries(attrs)) { 32 | pre.setAttribute(key, value); 33 | code.setAttribute(key, value); 34 | } 35 | 36 | code.textContent = value; 37 | pre.appendChild(code); 38 | 39 | // eslint-disable-next-line no-undef 40 | window.Prism.highlightElement(code); 41 | 42 | return code.innerHTML 43 | .replace(MULTILINE_TOKEN_SPAN, (match, token) => { 44 | return match.replace(/\n/g, `\n`); 45 | }) 46 | .split(/\n/) 47 | .reduce((memo, line, idx) => { 48 | return memo.concat( 49 | range.includes(idx + 1) 50 | ? `${line}\n` 51 | : `${line}\n`, 52 | ); 53 | }, ''); 54 | }; 55 | 56 | const loadLanguages = (parsingContext) => { 57 | const loadedLanguages = new Set(); 58 | 59 | const languages = Object.keys(components.languages).filter( 60 | (l) => l !== 'meta', 61 | ); 62 | 63 | const loaded = [ 64 | ...loadedLanguages, 65 | ...Object.keys(parsingContext.Prism.languages), 66 | ]; 67 | 68 | getLoader(components, languages, loaded).load((lang) => { 69 | if (!(lang in components.languages)) { 70 | console.warn('Language does not exist: ' + lang); 71 | return; 72 | } 73 | 74 | const filename = require.resolve(`prismjs/components/prism-${lang}`); 75 | runInContext(RUN(readFileSync(filename, 'utf-8')), parsingContext, { 76 | filename, 77 | }); 78 | 79 | loadedLanguages.add(lang); 80 | }); 81 | 82 | return Object.entries(components.languages).reduce( 83 | (memo, [name, { alias }]) => { 84 | return memo.concat(name).concat(alias).filter(Boolean); 85 | }, 86 | [], 87 | ); 88 | }; 89 | 90 | const RUN = (src) => { 91 | return ` 92 | window.Prism = Prism; 93 | 94 | try { 95 | const self = window; 96 | ${src}; 97 | } catch(err) { 98 | console.error(err); 99 | }; 100 | `; 101 | }; 102 | 103 | const deserialize = (html) => { 104 | const document = parse5.parse(html, { 105 | treeAdapter: htmlparser2Adapter, 106 | }); 107 | 108 | const toHast = ({ type, name, attribs = {}, data: value, children = [] }) => { 109 | const { class: className = '', ...attrs } = attribs; 110 | 111 | const _children = children.map(toHast); 112 | const properties = { 113 | ...attrs, 114 | className: className.split(/\s/).filter(Boolean), 115 | }; 116 | 117 | return { 118 | type: type === 'tag' ? 'element' : 'text', 119 | value, 120 | tagName: name, 121 | data: { 122 | hName: name, 123 | hProperties: properties, 124 | hChildren: _children, 125 | }, 126 | properties, 127 | children: _children, 128 | }; 129 | }; 130 | 131 | return document.children 132 | .pop() 133 | .children.find(({ name }) => name === 'body') 134 | .children.map(toHast); 135 | }; 136 | 137 | module.exports = ({ plugins = [] }) => { 138 | const { window } = new JSDOM(''); 139 | const parsingContext = createContext(window); 140 | 141 | const prismjs = require.resolve('prismjs'); 142 | runInContext(RUN(readFileSync(prismjs, 'utf-8')), parsingContext, { 143 | filename: prismjs, 144 | }); 145 | 146 | // load languages into the Prism object 147 | const languages = loadLanguages(parsingContext); 148 | const highlightElement = runInContext( 149 | domHighlight.toString(), 150 | parsingContext, 151 | ); 152 | 153 | // load plugins into the Prism object 154 | plugins.forEach((pl) => { 155 | const plugin = PLUGINS.includes(pl) 156 | ? `prismjs/plugins/${pl}/prism-${pl}` 157 | : pl; 158 | 159 | const filename = require.resolve(plugin); 160 | return runInContext(RUN(readFileSync(filename, 'utf-8')), parsingContext, { 161 | filename, 162 | }); 163 | }); 164 | 165 | return ({ lang, value, attrs, range = [] }) => { 166 | const fallback = () => { 167 | return [ 168 | { 169 | type: 'text', 170 | value: escapeHtml(value), 171 | }, 172 | ]; 173 | }; 174 | 175 | if (!lang) { 176 | fallback(); 177 | } 178 | 179 | if ( 180 | !languages.includes(lang.replace(/^diff-/, '')) && 181 | lang !== 'treeview' 182 | ) { 183 | return fallback(); 184 | } 185 | 186 | return deserialize(highlightElement(value, attrs, range)); 187 | }; 188 | }; 189 | 190 | module.exports.PLUGINS = PLUGINS; 191 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | const classNames = require('classnames'); 2 | const { CssSelectorParser } = require('css-selector-parser'); 3 | const map = require('unist-util-map'); 4 | const rangeParser = require('parse-numeric-range'); 5 | const createHighlighter = require('./highlight'); 6 | 7 | const h = (type, attrs = {}, children = []) => { 8 | return { 9 | type: 'element', 10 | tagName: type, 11 | data: { 12 | hName: type, 13 | hProperties: attrs, 14 | hChildren: children, 15 | }, 16 | properties: attrs, 17 | children, 18 | }; 19 | }; 20 | 21 | const selectorToAttrs = (selector) => { 22 | const parser = new CssSelectorParser(); 23 | const { rule } = parser.parse(selector); 24 | const { attrs = [] } = rule; 25 | 26 | return attrs.reduce((memo, { name, operator, value }) => { 27 | if (operator !== '=') { 28 | return memo; 29 | } 30 | 31 | const isClass = name === 'class'; 32 | const newValue = isClass 33 | ? [memo[name] || ''].concat(value).join(' ') 34 | : value; 35 | 36 | return Object.assign(memo, { 37 | [name]: newValue, 38 | }); 39 | }, {}); 40 | }; 41 | 42 | const parseLang = (str) => { 43 | const match = (regexp) => { 44 | const m = (str || '').match(regexp); 45 | return Array.isArray(m) ? m.filter(Boolean) : []; 46 | }; 47 | 48 | const [lang = 'unknown'] = match(/^[a-zA-Z\d-]*/g); 49 | const selectors = match(/\[(.*?)\]/g).join(''); 50 | 51 | const attrs = selectors.length ? selectorToAttrs(selectors) : {}; 52 | const className = classNames(`language-${lang}`, attrs.class); 53 | const { legend = '', ...restAttrs } = attrs; 54 | 55 | const range = rangeParser( 56 | match(/\{(.*?)\}$/g) 57 | .join(',') 58 | .replace(/^\{/, '') 59 | .replace(/\}$/, ''), 60 | ); 61 | 62 | return { 63 | lang, 64 | legend, 65 | range, 66 | attrs: { 67 | ...restAttrs, 68 | class: className, 69 | }, 70 | }; 71 | }; 72 | 73 | module.exports = (options = {}) => (tree) => { 74 | const highlight = createHighlighter(options); 75 | const { transformInlineCode = false } = options; 76 | 77 | return map(tree, (node) => { 78 | const { type, tagName } = node; 79 | 80 | if ( 81 | !['code', 'inlineCode'].includes(type) && 82 | !['code', 'inlineCode'].includes(tagName) 83 | ) { 84 | return node; 85 | } 86 | 87 | if ( 88 | (type === 'inlineCode' && !transformInlineCode) || 89 | (type === 'tagName' && !transformInlineCode) 90 | ) { 91 | return node; 92 | } 93 | 94 | const { value, properties = {}, children = [] } = node; 95 | const { className: classNameArr = [] } = properties; 96 | const langClassName = classNameArr 97 | .map((lang) => lang.replace(/language-/, '')) 98 | .join(' '); 99 | 100 | const langToken = node.lang || langClassName; 101 | const { lang = 'unknown', attrs, legend, range } = parseLang(langToken); 102 | const { class: className = '', ...restAttrs } = attrs; 103 | 104 | const code = h( 105 | 'code', 106 | { className: `language-${lang}` }, 107 | highlight({ 108 | lang, 109 | value: 110 | value || 111 | children 112 | .filter(({ type }) => type === 'text') 113 | .map(({ value }) => value) 114 | .pop(), 115 | attrs, 116 | range, 117 | }), 118 | ); 119 | 120 | const pre = h( 121 | 'div', 122 | { className: `remark-highlight` }, 123 | [ 124 | h( 125 | 'pre', 126 | { 127 | ...restAttrs, 128 | className: className.split(/\s/), 129 | }, 130 | [code], 131 | ), 132 | legend ? h('legend', {}, [{ type: 'text', value: legend }]) : null, 133 | ].filter(Boolean), 134 | ); 135 | 136 | return /^inline/.test(type) ? code : pre; 137 | }); 138 | }; 139 | -------------------------------------------------------------------------------- /test/fixtures/all.md: -------------------------------------------------------------------------------- 1 | # hello from `remark-prism` 2 | 3 | welcome all. 4 | 5 | ```markdown 6 | [Text you want to see](http://url-goes-here.com) 7 | ``` 8 | 9 | ```bash[data-user="chris"][data-host="remotehost"][data-output="2,4-8"] 10 | pwd 11 | /usr/home/chris/bin 12 | ls -la 13 | total 2 14 | drwxr-xr-x 2 chris chris 11 Jan 10 16:48 . 15 | drwxr--r-x 45 chris chris 92 Feb 14 11:10 .. 16 | -rwxr-xr-x 1 chris chris 444 Aug 25 2013 backup 17 | -rwxr-xr-x 1 chris chris 642 Jan 17 14:42 deploy 18 | ``` 19 | 20 | ```css 21 | div { 22 | border: 40px solid transparent; 23 | border-image: 33.334% 24 | padding: 1em; 25 | max-width: 20em; 26 | font: 130%/1.6 Baskerville, Palatino, serif; 27 | border-image: 33.334% url('data:image/svg+xml;utf8,'); 28 | } 29 | ``` 30 | 31 | ```diff-javascript[class="diff-highlight"] 32 | @@ -4,6 +4,5 @@ 33 | - let foo = bar.baz([1, 2, 3]); 34 | - foo = foo + 1; 35 | + const foo = bar.baz([1, 2, 3]) + 1; 36 | console.log(`foo: ${foo}`); 37 | ``` 38 | 39 | ```css 40 | span.foo { 41 | background-color: navy; 42 | color: #bfd; 43 | } 44 | 45 | span.bar { 46 | background: rgba(105, 0, 12, 0.38); 47 | color: hsl(30, 100%, 50%); 48 | border-color: transparent; 49 | } 50 | ``` 51 | 52 | ```html[legend="file.html"]{1,3-4,8} 53 | 54 | 55 | 56 | 57 | 58 |
Autolinking in raw text: http://prismjs.com
25 | ``` 26 | 27 | ```markdown 28 | [Text you want to see](http://url-goes-here.com) 29 | ``` 30 | -------------------------------------------------------------------------------- /test/fixtures/command-line.md: -------------------------------------------------------------------------------- 1 | ```bash[data-user="chris"][data-host="remotehost"][data-output="2,4-8"] 2 | pwd 3 | /usr/home/chris/bin 4 | ls -la 5 | total 2 6 | drwxr-xr-x 2 chris chris 11 Jan 10 16:48 . 7 | drwxr--r-x 45 chris chris 92 Feb 14 11:10 .. 8 | -rwxr-xr-x 1 chris chris 444 Aug 25 2013 backup 9 | -rwxr-xr-x 1 chris chris 642 Jan 17 14:42 deploy 10 | ``` 11 | -------------------------------------------------------------------------------- /test/fixtures/data-uri-highlight.md: -------------------------------------------------------------------------------- 1 | ```css 2 | div { 3 | border: 40px solid transparent; 4 | border-image: 33.334% 5 | padding: 1em; 6 | max-width: 20em; 7 | font: 130%/1.6 Baskerville, Palatino, serif; 8 | border-image: 33.334% url('data:image/svg+xml;utf8,'); 9 | } 10 | ``` 11 | -------------------------------------------------------------------------------- /test/fixtures/diff-highlight.md: -------------------------------------------------------------------------------- 1 | ```diff 2 | @@ -4,6 +4,5 @@ 3 | - let foo = bar.baz([1, 2, 3]); 4 | - foo = foo + 1; 5 | + const foo = bar.baz([1, 2, 3]) + 1; 6 | console.log(`foo: ${foo}`); 7 | ``` 8 | 9 | ```diff[class="diff-highlight"] 10 | @@ -4,6 +4,5 @@ 11 | - let foo = bar.baz([1, 2, 3]); 12 | - foo = foo + 1; 13 | + const foo = bar.baz([1, 2, 3]) + 1; 14 | console.log(`foo: ${foo}`); 15 | ``` 16 | 17 | ```diff-javascript[class="diff-highlight"] 18 | @@ -4,6 +4,5 @@ 19 | - let foo = bar.baz([1, 2, 3]); 20 | - foo = foo + 1; 21 | + const foo = bar.baz([1, 2, 3]) + 1; 22 | console.log(`foo: ${foo}`); 23 | ``` 24 | -------------------------------------------------------------------------------- /test/fixtures/inline-color.md: -------------------------------------------------------------------------------- 1 | ```css 2 | span.foo { 3 | background-color: navy; 4 | color: #bfd; 5 | } 6 | 7 | span.bar { 8 | background: rgba(105, 0, 12, 0.38); 9 | color: hsl(30, 100%, 50%); 10 | border-color: transparent; 11 | } 12 | ``` 13 | 14 | ```html 15 | 16 | 17 | 18 | 19 |/**
6 | * Prism: Lightweight, robust, elegant syntax highlighting
7 | * MIT license http://www.opensource.org/licenses/mit-license.php/
8 | * @author Lea Verou http://lea.verou.me
9 | * Reach Lea at fake@email.com (no, not really)
10 | * And this is a Markdown link. Sweet, huh?
11 | */
12 | var foo = 5;
13 | // And a single line comment http://google.com
14 |
15 | @font-face {
20 | src: url(http://lea.verou.me/logo.otf);
21 | font-family: 'LeaVerou';
22 | }
23 |
24 | <!-- Links in HTML, woo!
29 | Lea Verou http://lea.verou.me or, with Markdown, Lea Verou -->
30 | <img src="http://prismjs.com/img/spectrum.png" alt="In attributes too!" />
31 | <p>Autolinking in raw text: http://prismjs.com</p>
32 |
33 | [Text you want to see](http://url-goes-here.com)
38 |
39 | /**
7 | * Prism: Lightweight, robust, elegant syntax highlighting
8 | * MIT license http://www.opensource.org/licenses/mit-license.php/
9 | * @author Lea Verou http://lea.verou.me
10 | * Reach Lea at fake@email.com (no, not really)
11 | * And this is a Markdown link. Sweet, huh?
12 | */
13 | var foo = 5;
14 | // And a single line comment http://google.com
15 |
16 | @font-face {
22 | src: url(http://lea.verou.me/logo.otf);
23 | font-family: 'LeaVerou';
24 | }
25 |
26 | <!-- Links in HTML, woo!
32 | Lea Verou http://lea.verou.me or, with Markdown, Lea Verou -->
33 | <img src="http://prismjs.com/img/spectrum.png" alt="In attributes too!" />
34 | <p>Autolinking in raw text: http://prismjs.com</p>
35 |
36 | [Text you want to see](http://url-goes-here.com)
42 |
43 | /**
6 | * Prism: Lightweight, robust, elegant syntax highlighting
7 | * MIT license http://www.opensource.org/licenses/mit-license.php/
8 | * @author Lea Verou http://lea.verou.me
9 | * Reach Lea at fake@email.com (no, not really)
10 | * And this is a Markdown link. Sweet, huh?
11 | */
12 | var foo = 5;
13 | // And a single line comment http://google.com
14 |
15 | @font-face {
20 | src: url(http://lea.verou.me/logo.otf);
21 | font-family: 'LeaVerou';
22 | }
23 |
24 | <!-- Links in HTML, woo!
29 | Lea Verou http://lea.verou.me or, with Markdown, Lea Verou -->
30 | <img src="http://prismjs.com/img/spectrum.png" alt="In attributes too!" />
31 | <p>Autolinking in raw text: http://prismjs.com</p>
32 |
33 | [Text you want to see](http://url-goes-here.com)
38 |
39 | pwd
9 | /usr/home/chris/bin
10 | ls -la
11 | total 2
12 | drwxr-xr-x 2 chris chris 11 Jan 10 16:48 .
13 | drwxr--r-x 45 chris chris 92 Feb 14 11:10 ..
14 | -rwxr-xr-x 1 chris chris 444 Aug 25 2013 backup
15 | -rwxr-xr-x 1 chris chris 642 Jan 17 14:42 deploy
16 |
17 | pwd
10 | /usr/home/chris/bin
11 | ls -la
12 | total 2
13 | drwxr-xr-x 2 chris chris 11 Jan 10 16:48 .
14 | drwxr--r-x 45 chris chris 92 Feb 14 11:10 ..
15 | -rwxr-xr-x 1 chris chris 444 Aug 25 2013 backup
16 | -rwxr-xr-x 1 chris chris 642 Jan 17 14:42 deploy
17 |
18 | pwd
9 | /usr/home/chris/bin
10 | ls -la
11 | total 2
12 | drwxr-xr-x 2 chris chris 11 Jan 10 16:48 .
13 | drwxr--r-x 45 chris chris 92 Feb 14 11:10 ..
14 | -rwxr-xr-x 1 chris chris 444 Aug 25 2013 backup
15 | -rwxr-xr-x 1 chris chris 642 Jan 17 14:42 deploy
16 |
17 | div {
6 | border: 40px solid transparent;
7 | border-image: 33.334%
8 | padding: 1em;
9 | max-width: 20em;
10 | font: 130%/1.6 Baskerville, Palatino, serif;
11 | border-image: 33.334% url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Layer_1" x="0px" y="0px" viewBox="0 0 100 100" enable-background="new 0 0 100 100" xml:space="preserve" height="100px" width="100px"><g><path d="M28.1,36.6c4.6,1.9,12.2,1.6,20.9,1.1c8.9-0.4,19-0.9,28.9,0.9c6.3,1.2,11.9,3.1,16.8,6c-1.5-12.2-7.9-23.7-18.6-31.3 c-4.9-0.2-9.9,0.3-14.8,1.4C47.8,17.9,36.2,25.6,28.1,36.6z"/><path d="M70.3,9.8C57.5,3.4,42.8,3.6,30.5,9.5c-3,6-8.4,19.6-5.3,24.9c8.6-11.7,20.9-19.8,35.2-23.1C63.7,10.5,67,10,70.3,9.8z"/><path d="M16.5,51.3c0.6-1.7,1.2-3.4,2-5.1c-3.8-3.4-7.5-7-11-10.8c-2.1,6.1-2.8,12.5-2.3,18.7C9.6,51.1,13.4,50.2,16.5,51.3z"/><path d="M9,31.6c3.5,3.9,7.2,7.6,11.1,11.1c0.8-1.6,1.7-3.1,2.6-4.6c0.1-0.2,0.3-0.4,0.4-0.6c-2.9-3.3-3.1-9.2-0.6-17.6 c0.8-2.7,1.8-5.3,2.7-7.4c-5.2,3.4-9.8,8-13.3,13.7C10.8,27.9,9.8,29.7,9,31.6z"/><path d="M15.4,54.7c-2.6-1-6.1,0.7-9.7,3.4c1.2,6.6,3.9,13,8,18.5C13,69.3,13.5,61.8,15.4,54.7z"/><path d="M39.8,57.6C54.3,66.7,70,73,86.5,76.4c0.6-0.8,1.1-1.6,1.7-2.5c4.8-7.7,7-16.3,6.8-24.8c-13.8-9.3-31.3-8.4-45.8-7.7 c-9.5,0.5-17.8,0.9-23.2-1.7c-0.1,0.1-0.2,0.3-0.3,0.4c-1,1.7-2,3.4-2.9,5.1C28.2,49.7,33.8,53.9,39.8,57.6z"/><path d="M26.2,88.2c3.3,2,6.7,3.6,10.2,4.7c-3.5-6.2-6.3-12.6-8.8-18.5c-3.1-7.2-5.8-13.5-9-17.2c-1.9,8-2,16.4-0.3,24.7 C20.6,84.2,23.2,86.3,26.2,88.2z"/><path d="M30.9,73c2.9,6.8,6.1,14.4,10.5,21.2c15.6,3,32-2.3,42.6-14.6C67.7,76,52.2,69.6,37.9,60.7C32,57,26.5,53,21.3,48.6 c-0.6,1.5-1.2,3-1.7,4.6C24.1,57.1,27.3,64.5,30.9,73z"/></g></svg>');
12 | }
13 |
14 | div {
7 | border: 40px solid transparent;
8 | border-image: 33.334%
9 | padding: 1em;
10 | max-width: 20em;
11 | font: 130%/1.6 Baskerville, Palatino, serif;
12 | border-image: 33.334% url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Layer_1" x="0px" y="0px" viewBox="0 0 100 100" enable-background="new 0 0 100 100" xml:space="preserve" height="100px" width="100px"><g><path d="M28.1,36.6c4.6,1.9,12.2,1.6,20.9,1.1c8.9-0.4,19-0.9,28.9,0.9c6.3,1.2,11.9,3.1,16.8,6c-1.5-12.2-7.9-23.7-18.6-31.3 c-4.9-0.2-9.9,0.3-14.8,1.4C47.8,17.9,36.2,25.6,28.1,36.6z"/><path d="M70.3,9.8C57.5,3.4,42.8,3.6,30.5,9.5c-3,6-8.4,19.6-5.3,24.9c8.6-11.7,20.9-19.8,35.2-23.1C63.7,10.5,67,10,70.3,9.8z"/><path d="M16.5,51.3c0.6-1.7,1.2-3.4,2-5.1c-3.8-3.4-7.5-7-11-10.8c-2.1,6.1-2.8,12.5-2.3,18.7C9.6,51.1,13.4,50.2,16.5,51.3z"/><path d="M9,31.6c3.5,3.9,7.2,7.6,11.1,11.1c0.8-1.6,1.7-3.1,2.6-4.6c0.1-0.2,0.3-0.4,0.4-0.6c-2.9-3.3-3.1-9.2-0.6-17.6 c0.8-2.7,1.8-5.3,2.7-7.4c-5.2,3.4-9.8,8-13.3,13.7C10.8,27.9,9.8,29.7,9,31.6z"/><path d="M15.4,54.7c-2.6-1-6.1,0.7-9.7,3.4c1.2,6.6,3.9,13,8,18.5C13,69.3,13.5,61.8,15.4,54.7z"/><path d="M39.8,57.6C54.3,66.7,70,73,86.5,76.4c0.6-0.8,1.1-1.6,1.7-2.5c4.8-7.7,7-16.3,6.8-24.8c-13.8-9.3-31.3-8.4-45.8-7.7 c-9.5,0.5-17.8,0.9-23.2-1.7c-0.1,0.1-0.2,0.3-0.3,0.4c-1,1.7-2,3.4-2.9,5.1C28.2,49.7,33.8,53.9,39.8,57.6z"/><path d="M26.2,88.2c3.3,2,6.7,3.6,10.2,4.7c-3.5-6.2-6.3-12.6-8.8-18.5c-3.1-7.2-5.8-13.5-9-17.2c-1.9,8-2,16.4-0.3,24.7 C20.6,84.2,23.2,86.3,26.2,88.2z"/><path d="M30.9,73c2.9,6.8,6.1,14.4,10.5,21.2c15.6,3,32-2.3,42.6-14.6C67.7,76,52.2,69.6,37.9,60.7C32,57,26.5,53,21.3,48.6 c-0.6,1.5-1.2,3-1.7,4.6C24.1,57.1,27.3,64.5,30.9,73z"/></g></svg>');
13 | }
14 |
15 | div {
6 | border: 40px solid transparent;
7 | border-image: 33.334%
8 | padding: 1em;
9 | max-width: 20em;
10 | font: 130%/1.6 Baskerville, Palatino, serif;
11 | border-image: 33.334% url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Layer_1" x="0px" y="0px" viewBox="0 0 100 100" enable-background="new 0 0 100 100" xml:space="preserve" height="100px" width="100px"><g><path d="M28.1,36.6c4.6,1.9,12.2,1.6,20.9,1.1c8.9-0.4,19-0.9,28.9,0.9c6.3,1.2,11.9,3.1,16.8,6c-1.5-12.2-7.9-23.7-18.6-31.3 c-4.9-0.2-9.9,0.3-14.8,1.4C47.8,17.9,36.2,25.6,28.1,36.6z"/><path d="M70.3,9.8C57.5,3.4,42.8,3.6,30.5,9.5c-3,6-8.4,19.6-5.3,24.9c8.6-11.7,20.9-19.8,35.2-23.1C63.7,10.5,67,10,70.3,9.8z"/><path d="M16.5,51.3c0.6-1.7,1.2-3.4,2-5.1c-3.8-3.4-7.5-7-11-10.8c-2.1,6.1-2.8,12.5-2.3,18.7C9.6,51.1,13.4,50.2,16.5,51.3z"/><path d="M9,31.6c3.5,3.9,7.2,7.6,11.1,11.1c0.8-1.6,1.7-3.1,2.6-4.6c0.1-0.2,0.3-0.4,0.4-0.6c-2.9-3.3-3.1-9.2-0.6-17.6 c0.8-2.7,1.8-5.3,2.7-7.4c-5.2,3.4-9.8,8-13.3,13.7C10.8,27.9,9.8,29.7,9,31.6z"/><path d="M15.4,54.7c-2.6-1-6.1,0.7-9.7,3.4c1.2,6.6,3.9,13,8,18.5C13,69.3,13.5,61.8,15.4,54.7z"/><path d="M39.8,57.6C54.3,66.7,70,73,86.5,76.4c0.6-0.8,1.1-1.6,1.7-2.5c4.8-7.7,7-16.3,6.8-24.8c-13.8-9.3-31.3-8.4-45.8-7.7 c-9.5,0.5-17.8,0.9-23.2-1.7c-0.1,0.1-0.2,0.3-0.3,0.4c-1,1.7-2,3.4-2.9,5.1C28.2,49.7,33.8,53.9,39.8,57.6z"/><path d="M26.2,88.2c3.3,2,6.7,3.6,10.2,4.7c-3.5-6.2-6.3-12.6-8.8-18.5c-3.1-7.2-5.8-13.5-9-17.2c-1.9,8-2,16.4-0.3,24.7 C20.6,84.2,23.2,86.3,26.2,88.2z"/><path d="M30.9,73c2.9,6.8,6.1,14.4,10.5,21.2c15.6,3,32-2.3,42.6-14.6C67.7,76,52.2,69.6,37.9,60.7C32,57,26.5,53,21.3,48.6 c-0.6,1.5-1.2,3-1.7,4.6C24.1,57.1,27.3,64.5,30.9,73z"/></g></svg>');
12 | }
13 |
14 | @@ -4,6 +4,5 @@
6 | - let foo = bar.baz([1, 2, 3]);
7 | - foo = foo + 1;
8 | + const foo = bar.baz([1, 2, 3]) + 1;
9 | console.log(`foo: ${foo}`);
10 |
11 | @@ -4,6 +4,5 @@
16 | - let foo = bar.baz([1, 2, 3]);
17 | - foo = foo + 1;
18 | + const foo = bar.baz([1, 2, 3]) + 1;
19 | console.log(`foo: ${foo}`);
20 |
21 | @@ -4,6 +4,5 @@
26 | - let foo = bar.baz([1, 2, 3]);
27 | - foo = foo + 1;
28 | + const foo = bar.baz([1, 2, 3]) + 1;
29 | console.log(`foo: ${foo}`);
30 |
31 | @@ -4,6 +4,5 @@
7 | - let foo = bar.baz([1, 2, 3]);
8 | - foo = foo + 1;
9 | + const foo = bar.baz([1, 2, 3]) + 1;
10 | console.log(`foo: ${foo}`);
11 |
12 | @@ -4,6 +4,5 @@
18 | - let foo = bar.baz([1, 2, 3]);
19 | - foo = foo + 1;
20 | + const foo = bar.baz([1, 2, 3]) + 1;
21 | console.log(`foo: ${foo}`);
22 |
23 | @@ -4,6 +4,5 @@
29 | - let foo = bar.baz([1, 2, 3]);
30 | - foo = foo + 1;
31 | + const foo = bar.baz([1, 2, 3]) + 1;
32 | console.log(`foo: ${foo}`);
33 |
34 | @@ -4,6 +4,5 @@
6 | - let foo = bar.baz([1, 2, 3]);
7 | - foo = foo + 1;
8 | + const foo = bar.baz([1, 2, 3]) + 1;
9 | console.log(`foo: ${foo}`);
10 |
11 | @@ -4,6 +4,5 @@
16 | - let foo = bar.baz([1, 2, 3]);
17 | - foo = foo + 1;
18 | + const foo = bar.baz([1, 2, 3]) + 1;
19 | console.log(`foo: ${foo}`);
20 |
21 | @@ -4,6 +4,5 @@
26 | - let foo = bar.baz([1, 2, 3]);
27 | - foo = foo + 1;
28 | + const foo = bar.baz([1, 2, 3]) + 1;
29 | console.log(`foo: ${foo}`);
30 |
31 | span.foo {
6 | background-color: navy;
7 | color: #bfd;
8 | }
9 |
10 | span.bar {
11 | background: rgba(105, 0, 12, 0.38);
12 | color: hsl(30, 100%, 50%);
13 | border-color: transparent;
14 | }
15 |
16 | <!DOCTYPE html>
21 | <html lang="en">
22 | <head>
23 | <meta charset="utf-8" />
24 | <title>Example</title>
25 | <style>
26 | a.not-a-class {
27 | color: red;
28 | }
29 | </style>
30 | </head>
31 | <body style="color:black"></body>
32 | </html>
33 |
34 | span.foo {
7 | background-color: navy;
8 | color: #bfd;
9 | }
10 |
11 | span.bar {
12 | background: rgba(105, 0, 12, 0.38);
13 | color: hsl(30, 100%, 50%);
14 | border-color: transparent;
15 | }
16 |
17 | <!DOCTYPE html>
23 | <html lang="en">
24 | <head>
25 | <meta charset="utf-8" />
26 | <title>Example</title>
27 | <style>
28 | a.not-a-class {
29 | color: red;
30 | }
31 | </style>
32 | </head>
33 | <body style="color:black"></body>
34 | </html>
35 |
36 | span.foo {
6 | background-color: navy;
7 | color: #bfd;
8 | }
9 |
10 | span.bar {
11 | background: rgba(105, 0, 12, 0.38);
12 | color: hsl(30, 100%, 50%);
13 | border-color: transparent;
14 | }
15 |
16 | <!DOCTYPE html>
21 | <html lang="en">
22 | <head>
23 | <meta charset="utf-8" />
24 | <title>Example</title>
25 | <style>
26 | a.not-a-class {
27 | color: red;
28 | }
29 | </style>
30 | </head>
31 | <body style="color:black"></body>
32 | </html>
33 |
34 | x<span>a</span>y
6 |
7 | x<span>a</span>y
7 |
8 | x<span>a</span>y
6 |
7 | <!DOCTYPE html>
6 | <html lang="en">
7 | <head>
8 | <meta charset="UTF-8" />
9 | <meta name="viewport" content="width=device-width, initial-scale=1.0" />
10 | <title>Hello World!</title>
11 | </head>
12 | <body>
13 | <h1>Hello World!</h1>
14 | </body>
15 | </html>
16 |
17 |
18 | <!DOCTYPE html>
7 | <html lang="en">
8 | <head>
9 | <meta charset="UTF-8" />
10 | <meta name="viewport" content="width=device-width, initial-scale=1.0" />
11 | <title>Hello World!</title>
12 | </head>
13 | <body>
14 | <h1>Hello World!</h1>
15 | </body>
16 | </html>
17 |
18 |
19 | <!DOCTYPE html>
6 | <html lang="en">
7 | <head>
8 | <meta charset="UTF-8" />
9 | <meta name="viewport" content="width=device-width, initial-scale=1.0" />
10 | <title>Hello World!</title>
11 | </head>
12 | <body>
13 | <h1>Hello World!</h1>
14 | </body>
15 | </html>
16 |
17 |
18 | <!DOCTYPE html>
6 | <html lang="en">
7 | <head>
8 | <meta charset="UTF-8" />
9 | <meta name="viewport" content="width=device-width, initial-scale=1.0" />
10 | <title>Hello World!</title>
11 | </head>
12 | <body>
13 | <h1>Hello World!</h1>
14 | </body>
15 | </html>
16 |
17 | <!DOCTYPE html>
22 | <html lang="en">
23 | <head>
24 | <meta charset="UTF-8" />
25 | <meta name="viewport" content="width=device-width, initial-scale=1.0" />
26 | <title>Hello World!</title>
27 | </head>
28 | <body>
29 | <h1>Hello World!</h1>
30 | </body>
31 | </html>
32 |
33 | export default () => {
38 | // register current used theme
39 | const [theme, setTheme] = React.useState(themes.light);
40 |
41 | // handle the radio changes
42 | const handleChange = ({ target }) => {
43 | // based on the radio value, toggle to the correct theme
44 | return setTheme(themes[target.value]);
45 | };
46 |
47 | return (
48 | <ThemeProvider value={theme}>
49 | <Button>I am styled by theme context!</Button>
50 | <form onChange={handleChange}>
51 | <p>Please select your theme:</p>
52 | <input type="radio" id="light" name="theme" value="light" />
53 | <label for="light">Light</label>
54 | <input type="radio" id="dark" name="theme" value="dark" />
55 | <label for="dark">Dark</label>
56 | </form>
57 | </ThemeProvider>
58 | );
59 | };
60 |
61 | <!DOCTYPE html>
6 | <html lang="en">
7 | <head>
8 | <meta charset="UTF-8" />
9 | <meta name="viewport" content="width=device-width, initial-scale=1.0" />
10 | <title>Hello World!</title>
11 | </head>
12 | <body>
13 | <h1>Hello World!</h1>
14 | </body>
15 | </html>
16 |
17 | <!DOCTYPE html>
22 | <html lang="en">
23 | <head>
24 | <meta charset="UTF-8" />
25 | <meta name="viewport" content="width=device-width, initial-scale=1.0" />
26 | <title>Hello World!</title>
27 | </head>
28 | <body>
29 | <h1>Hello World!</h1>
30 | </body>
31 | </html>
32 |
33 | export default () => {
38 | // register current used theme
39 | const [theme, setTheme] = React.useState(themes.light);
40 |
41 | // handle the radio changes
42 | const handleChange = ({ target }) => {
43 | // based on the radio value, toggle to the correct theme
44 | return setTheme(themes[target.value]);
45 | };
46 |
47 | return (
48 | <ThemeProvider value={theme}>
49 | <Button>I am styled by theme context!</Button>
50 | <form onChange={handleChange}>
51 | <p>Please select your theme:</p>
52 | <input type="radio" id="light" name="theme" value="light" />
53 | <label for="light">Light</label>
54 | <input type="radio" id="dark" name="theme" value="dark" />
55 | <label for="dark">Dark</label>
56 | </form>
57 | </ThemeProvider>
58 | );
59 | };
60 |
61 | <!DOCTYPE html>
6 | <html lang="en">
7 | <head>
8 | <meta charset="UTF-8" />
9 | <meta name="viewport" content="width=device-width, initial-scale=1.0" />
10 | <title>Hello World!</title>
11 | </head>
12 | <body>
13 | <h1>Hello World!</h1>
14 | </body>
15 | </html>
16 |
17 | <!DOCTYPE html>
22 | <html lang="en">
23 | <head>
24 | <meta charset="UTF-8" />
25 | <meta name="viewport" content="width=device-width, initial-scale=1.0" />
26 | <title>Hello World!</title>
27 | </head>
28 | <body>
29 | <h1>Hello World!</h1>
30 | </body>
31 | </html>
32 |
33 | <!DOCTYPE html>
38 | <html lang="en">
39 | <head>
40 | <meta charset="UTF-8" />
41 | <meta name="viewport" content="width=device-width, initial-scale=1.0" />
42 | <title>Hello World!</title>
43 | </head>
44 | <body>
45 | <h1>Hello World!</h1>
46 | </body>
47 | </html>
48 |
49 | <!DOCTYPE html>
6 | <html lang="en">
7 | <head>
8 | <meta charset="UTF-8" />
9 | <meta name="viewport" content="width=device-width, initial-scale=1.0" />
10 | <title>Hello World!</title>
11 | </head>
12 | <body>
13 | <h1>Hello World!</h1>
14 | </body>
15 | </html>
16 |
17 | <!DOCTYPE html>
22 | <html lang="en">
23 | <head>
24 | <meta charset="UTF-8" />
25 | <meta name="viewport" content="width=device-width, initial-scale=1.0" />
26 | <title>Hello World!</title>
27 | </head>
28 | <body>
29 | <h1>Hello World!</h1>
30 | </body>
31 | </html>
32 |
33 | <!DOCTYPE html>
38 | <html lang="en">
39 | <head>
40 | <meta charset="UTF-8" />
41 | <meta name="viewport" content="width=device-width, initial-scale=1.0" />
42 | <title>Hello World!</title>
43 | </head>
44 | <body>
45 | <h1>Hello World!</h1>
46 | </body>
47 | </html>
48 |
49 | hello
4 | world
5 | hello
7 | world
8 | hello
4 | world
5 | <!DOCTYPE html>
6 | <html lang="en">
7 | <head>
8 | <meta charset="UTF-8" />
9 | <meta name="viewport" content="width=device-width, initial-scale=1.0" />
10 | <title>Hello World!</title>
11 | </head>
12 | <body>
13 | <h1>Hello World!</h1>
14 | </body>
15 | </html>
16 |
17 | <!DOCTYPE html>
7 | <html lang="en">
8 | <head>
9 | <meta charset="UTF-8" />
10 | <meta name="viewport" content="width=device-width, initial-scale=1.0" />
11 | <title>Hello World!</title>
12 | </head>
13 | <body>
14 | <h1>Hello World!</h1>
15 | </body>
16 | </html>
17 |
18 | <!DOCTYPE html>
6 | <html lang="en">
7 | <head>
8 | <meta charset="UTF-8" />
9 | <meta name="viewport" content="width=device-width, initial-scale=1.0" />
10 | <title>Hello World!</title>
11 | </head>
12 | <body>
13 | <h1>Hello World!</h1>
14 | </body>
15 | </html>
16 |
17 | .
6 | ├── .eslintignore
7 | ├── .eslintrc
8 | ├── .gitignore
9 | ├── .prettierignore
10 | ├── .prettierrc
11 | ├── .yarnrc.yml
12 | ├── README.md
13 | ├── index.js
14 | ├── package.json
15 | ├── test
16 | │ ├── fixtures
17 | │ └── index.js
18 | └── yarn.lock
19 |
20 | 7 directories, 41 files
21 |
22 | .
7 | ├── .eslintignore
8 | ├── .eslintrc
9 | ├── .gitignore
10 | ├── .prettierignore
11 | ├── .prettierrc
12 | ├── .yarnrc.yml
13 | ├── README.md
14 | ├── index.js
15 | ├── package.json
16 | ├── test
17 | │ ├── fixtures
18 | │ └── index.js
19 | └── yarn.lock
20 |
21 | 7 directories, 41 files
22 |
23 | .
6 | ├── .eslintignore
7 | ├── .eslintrc
8 | ├── .gitignore
9 | ├── .prettierignore
10 | ├── .prettierrc
11 | ├── .yarnrc.yml
12 | ├── README.md
13 | ├── index.js
14 | ├── package.json
15 | ├── test
16 | │ ├── fixtures
17 | │ └── index.js
18 | └── yarn.lock
19 |
20 | 7 directories, 41 files
21 |
22 |