From d10e8848e76a3db0bf17af0992323e70f2ec6166 Mon Sep 17 00:00:00 2001 From: Aaron Francis Date: Thu, 26 Aug 2021 21:56:04 -0500 Subject: [PATCH] First --- .github/workflows/publish.yml | 18 ++++++ .github/workflows/tests.yml | 15 +++++ .gitignore | 7 +++ .npmignore | 5 ++ README.md | 1 + babel.config.json | 8 +++ index.js | 76 +++++++++++++++++++++++++ package.json | 43 ++++++++++++++ tests/__snapshots__/render.test.js.snap | 7 +++ tests/render.test.js | 40 +++++++++++++ 10 files changed, 220 insertions(+) create mode 100644 .github/workflows/publish.yml create mode 100644 .github/workflows/tests.yml create mode 100644 .gitignore create mode 100644 .npmignore create mode 100644 README.md create mode 100644 babel.config.json create mode 100755 index.js create mode 100644 package.json create mode 100644 tests/__snapshots__/render.test.js.snap create mode 100644 tests/render.test.js diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..0b67ddb --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,18 @@ +name: Publish to NPM +on: + release: + types: [ created ] +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + # Setup .npmrc file to publish to npm + - uses: actions/setup-node@v2 + with: + node-version: '12.x' + registry-url: 'https://registry.npmjs.org' + - run: npm install + - run: npm publish + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..65cba4c --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,15 @@ +name: Tests +on: [ push, pull_request ] + +jobs: + test: + runs-on: ubuntu-latest + if: "!contains(github.event.head_commit.message, 'ci skip')" + steps: + - uses: actions/checkout@v2 + + - name: Install packages + run: npm install + + - name: Run tests + run: npm run test \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c2659c5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +torchlight.config.js +source +built +.idea +node_modules +tests/tmp +package-lock.json diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..f0c6be1 --- /dev/null +++ b/.npmignore @@ -0,0 +1,5 @@ +torchlight.config.js +source +built +.idea +tests/tmp \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..d79bd4b --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +See [torchlight.dev/docs/clients/cli](https://torchlight.dev/docs/clients/cli) for full docs. \ No newline at end of file diff --git a/babel.config.json b/babel.config.json new file mode 100644 index 0000000..e70e39e --- /dev/null +++ b/babel.config.json @@ -0,0 +1,8 @@ +{ + "presets": [ + "@babel/preset-env" + ], + "plugins": [ + "@babel/transform-runtime" + ] +} \ No newline at end of file diff --git a/index.js b/index.js new file mode 100755 index 0000000..4521d39 --- /dev/null +++ b/index.js @@ -0,0 +1,76 @@ +import parse5 from 'parse5' +import { map } from 'unist-util-map' +import { fromParse5 } from 'hast-util-from-parse5' + +import { torchlight, Block } from '@torchlight-api/torchlight-cli' + +export default function plugin (options = {}) { + torchlight.init(options.config) + + return tree => transform(tree, options) +} + +function transform (tree, options) { + const blocks = [] + + const withPlaceholders = map(tree, node => { + if (!isBlockCode(node)) { + return node + } + + const block = new Block({ + language: node.lang, + code: node.value + }) + + blocks.push(block) + + node.data = node.data ?? {} + node.data.torchlight = block + + return node + }) + + return torchlight.highlight(blocks).then(() => { + return map(withPlaceholders, node => { + if (!node?.data?.torchlight) { + return node + } + + const block = node.data.torchlight + const hast = fromParse5(parse5.parse(block.highlighted)) + + // The fragment that is returned from the API gets wrapped in a + // document and body, so we need to find the actual content + // inside all of the wrappers. + const highlighted = hast.children.pop().children.find(child => child.tagName === 'body').children + + const code = h('code', { + className: `language-${block.language}` + }, highlighted) + + return h('pre', { + className: [block.classes], + style: block.styles + }, [code]) + }) + }) +} + +const h = (type, attrs = {}, children = []) => { + return { + type: 'element', + tagName: type, + data: { + hName: type, + hProperties: attrs, + hChildren: children + }, + properties: attrs, + children + } +} + +function isBlockCode (node) { + return node.type === 'code' || node.tagName === 'code' +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..c177806 --- /dev/null +++ b/package.json @@ -0,0 +1,43 @@ +{ + "name": "remark-torchlight", + "version": "0.0.1", + "description": "A remark plugin for Torchlight - the syntax highlighting API.", + "main": "index.js", + "scripts": { + "test": "standard --env jest && jest" + }, + "keywords": [ + "syntax", + "highlighting", + "torchlight" + ], + "standard": { + "ignore": [ + "tests" + ] + }, + "jest": { + "clearMocks": true, + "transform": { + "^.+\\.[t|j]sx?$": "babel-jest" + }, + "transformIgnorePatterns": [] + }, + "author": "Aaron Francis (https://torchlight.dev)", + "license": "MIT", + "dependencies": { + "@torchlight-api/torchlight-cli": "^0.1.2", + "hast-util-from-parse5": "^7.1.0", + "parse5": "^6.0.1", + "unist-util-map": "^3.0.0" + }, + "devDependencies": { + "@babel/plugin-transform-runtime": "^7.15.0", + "@babel/preset-env": "^7.15.0", + "babel-jest": "^27.0.6", + "jest": "^27.0.6", + "remark": "^14.0.1", + "remark-html": "^14.0.0", + "standard": "^16.0.3" + } +} diff --git a/tests/__snapshots__/render.test.js.snap b/tests/__snapshots__/render.test.js.snap new file mode 100644 index 0000000..96fe56e --- /dev/null +++ b/tests/__snapshots__/render.test.js.snap @@ -0,0 +1,7 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`it tests 1`] = ` +"

this is test

+
highlighted
+" +`; diff --git a/tests/render.test.js b/tests/render.test.js new file mode 100644 index 0000000..30e9d0f --- /dev/null +++ b/tests/render.test.js @@ -0,0 +1,40 @@ +import torchlight from '../index' +import { remark } from 'remark' +import html from 'remark-html' +import {mockApi} from '@torchlight-api/torchlight-cli/tests/support/helpers' + +process.env.TORCHLIGHT_TOKEN = 'test' + +test('it tests', async () => { + + const markdown = `this _is_ [test](https://www.google.com) +\`\`\`js +// hello +\`\`\` +` + + const mock = mockApi(data => { + expect(data.blocks).toHaveLength(1) + + const block = data.blocks[0] + + expect(block.code).toEqual('// hello') + expect(block.language).toEqual('js') + + return [{ + ...block, + highlighted: 'highlighted', + classes: 'classes', + styles: 'style: 1;' + }] + }) + + const result = await remark() + .use(html) + .use(torchlight) + .process(markdown) + + expect(result.toString()).toMatchSnapshot() + expect(mock).toHaveBeenCalledTimes(1); + +}) \ No newline at end of file