├── app ├── .gitkeep └── initializers │ └── showdown-extension.js ├── addon ├── .gitkeep ├── styles │ └── addon.css └── initializers │ └── showdown-extension.js ├── tests ├── unit │ └── .gitkeep ├── integration │ └── .gitkeep ├── dummy │ ├── app │ │ ├── helpers │ │ │ └── .gitkeep │ │ ├── models │ │ │ └── .gitkeep │ │ ├── routes │ │ │ ├── .gitkeep │ │ │ └── application.js │ │ ├── components │ │ │ └── .gitkeep │ │ ├── controllers │ │ │ └── .gitkeep │ │ ├── templates │ │ │ └── application.hbs │ │ ├── styles │ │ │ └── app.css │ │ ├── router.js │ │ ├── app.js │ │ └── index.html │ ├── public │ │ ├── robots.txt │ │ └── example.md │ └── config │ │ ├── optional-features.json │ │ ├── targets.js │ │ ├── ember-cli-update.json │ │ ├── environment.js │ │ └── ember-try.js ├── test-helper.js ├── index.html ├── acceptance │ └── basic-test.js └── helpers │ └── index.js ├── .watchmanconfig ├── .template-lintrc.js ├── .stylelintrc.js ├── .stylelintignore ├── .eslintignore ├── .prettierignore ├── .prettierrc.js ├── .editorconfig ├── .gitignore ├── public └── images │ ├── ribbon-html.svg │ ├── ribbon-ts.svg │ ├── ribbon-pink.svg │ ├── ribbon-purple.svg │ ├── ribbon-js.svg │ └── ribbon-hbs.svg ├── changelog.template ├── .ember-cli ├── .npmignore ├── testem.js ├── CONTRIBUTING.md ├── ember-cli-build.js ├── LICENSE.md ├── index.js ├── .eslintrc.js ├── .github └── workflows │ └── ci.yml ├── RELEASE.md ├── README.md ├── CHANGELOG.md └── package.json /app/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /addon/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/unit/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/integration/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/dummy/app/helpers/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/dummy/app/models/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/dummy/app/routes/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/dummy/app/components/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/dummy/app/controllers/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.watchmanconfig: -------------------------------------------------------------------------------- 1 | { 2 | "ignore_dirs": ["dist"] 3 | } 4 | -------------------------------------------------------------------------------- /tests/dummy/public/robots.txt: -------------------------------------------------------------------------------- 1 | # http://www.robotstxt.org 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /.template-lintrc.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | extends: 'recommended', 5 | }; 6 | -------------------------------------------------------------------------------- /tests/dummy/app/templates/application.hbs: -------------------------------------------------------------------------------- 1 |

Ember Showdown Prism

2 | 3 | -------------------------------------------------------------------------------- /.stylelintrc.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | extends: ['stylelint-config-standard', 'stylelint-prettier/recommended'], 5 | }; 6 | -------------------------------------------------------------------------------- /tests/dummy/app/styles/app.css: -------------------------------------------------------------------------------- 1 | /* Ember supports plain CSS out of the box. More info: https://cli.emberjs.com/release/advanced-use/stylesheets/ */ 2 | -------------------------------------------------------------------------------- /.stylelintignore: -------------------------------------------------------------------------------- 1 | # unconventional files 2 | /blueprints/*/files/ 3 | 4 | # compiled output 5 | /dist/ 6 | 7 | # addons 8 | /.node_modules.ember-try/ 9 | -------------------------------------------------------------------------------- /app/initializers/showdown-extension.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable prettier/prettier */ 2 | export { default, initialize } from 'ember-showdown-prism/initializers/showdown-extension'; 3 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | # unconventional js 2 | /blueprints/*/files/ 3 | 4 | # compiled output 5 | /dist/ 6 | 7 | # misc 8 | /coverage/ 9 | !.* 10 | .*/ 11 | 12 | # ember-try 13 | /.node_modules.ember-try/ 14 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # unconventional js 2 | /blueprints/*/files/ 3 | 4 | # compiled output 5 | /dist/ 6 | 7 | # misc 8 | /coverage/ 9 | !.* 10 | .*/ 11 | 12 | # ember-try 13 | /.node_modules.ember-try/ 14 | -------------------------------------------------------------------------------- /tests/dummy/config/optional-features.json: -------------------------------------------------------------------------------- 1 | { 2 | "application-template-wrapper": false, 3 | "default-async-observers": true, 4 | "jquery-integration": false, 5 | "template-only-glimmer-components": true 6 | } 7 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | overrides: [ 5 | { 6 | files: '*.{js,ts}', 7 | options: { 8 | singleQuote: true, 9 | }, 10 | }, 11 | ], 12 | }; 13 | -------------------------------------------------------------------------------- /tests/dummy/app/routes/application.js: -------------------------------------------------------------------------------- 1 | import Route from '@ember/routing/route'; 2 | import fetch from 'fetch'; 3 | 4 | export default class ApplicationRoute extends Route { 5 | async model() { 6 | const result = await fetch('/example.md'); 7 | return result.text(); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /tests/dummy/app/router.js: -------------------------------------------------------------------------------- 1 | import EmberRouter from '@ember/routing/router'; 2 | import config from 'dummy/config/environment'; 3 | 4 | export default class Router extends EmberRouter { 5 | location = config.locationType; 6 | rootURL = config.rootURL; 7 | } 8 | 9 | Router.map(function () {}); 10 | -------------------------------------------------------------------------------- /tests/dummy/config/targets.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable prettier/prettier */ 2 | 'use strict'; 3 | 4 | const browsers = [ 5 | 'last 1 Chrome versions', 6 | 'last 1 Firefox versions', 7 | 'last 1 Safari versions', 8 | ]; 9 | 10 | module.exports = { 11 | browsers, 12 | node: 'current' 13 | }; 14 | -------------------------------------------------------------------------------- /tests/test-helper.js: -------------------------------------------------------------------------------- 1 | import Application from 'dummy/app'; 2 | import config from 'dummy/config/environment'; 3 | import * as QUnit from 'qunit'; 4 | import { setApplication } from '@ember/test-helpers'; 5 | import { setup } from 'qunit-dom'; 6 | import { start } from 'ember-qunit'; 7 | 8 | setApplication(Application.create(config.APP)); 9 | 10 | setup(QUnit.assert); 11 | 12 | start(); 13 | -------------------------------------------------------------------------------- /tests/dummy/app/app.js: -------------------------------------------------------------------------------- 1 | import Application from '@ember/application'; 2 | import Resolver from 'ember-resolver'; 3 | import loadInitializers from 'ember-load-initializers'; 4 | import config from 'dummy/config/environment'; 5 | 6 | export default class App extends Application { 7 | modulePrefix = config.modulePrefix; 8 | podModulePrefix = config.podModulePrefix; 9 | Resolver = Resolver; 10 | } 11 | 12 | loadInitializers(App, config.modulePrefix); 13 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | end_of_line = lf 9 | charset = utf-8 10 | trim_trailing_whitespace = true 11 | insert_final_newline = true 12 | indent_style = space 13 | indent_size = 2 14 | 15 | [*.hbs] 16 | insert_final_newline = false 17 | 18 | [*.{diff,md}] 19 | trim_trailing_whitespace = false 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # compiled output 2 | /dist/ 3 | 4 | # dependencies 5 | /node_modules/ 6 | 7 | # misc 8 | /.env* 9 | /.pnp* 10 | /.eslintcache 11 | /coverage/ 12 | /npm-debug.log* 13 | /testem.log 14 | /yarn-error.log 15 | 16 | # auto-changelog 17 | /.changelog/ 18 | 19 | # ember-try 20 | /.node_modules.ember-try/ 21 | /npm-shrinkwrap.json.ember-try 22 | /package.json.ember-try 23 | /package-lock.json.ember-try 24 | /yarn.lock.ember-try 25 | 26 | # broccoli-debug 27 | /DEBUG/ 28 | -------------------------------------------------------------------------------- /public/images/ribbon-html.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /changelog.template: -------------------------------------------------------------------------------- 1 | {{#each releases}} 2 | x.x.x / {{isoDate}} 3 | ================== 4 | {{#if merges}} 5 | {{#each merges}} 6 | * {{#if commit.breaking}}**Breaking change:** {{/if}}{{message}} #{{id}} from @{{githubIssue.user.login}} 7 | {{/each}} 8 | {{/if}} 9 | 10 | {{#if fixes}} 11 | {{#each fixes}} 12 | * FIX: {{#if commit.breaking}}**Breaking change:** {{/if}}{{commit.subject}}{{#each fixes}} {{#if href}}[`#{{id}}`]({{href}}){{/if}}{{/each}} 13 | {{/each}} 14 | {{/if}} 15 | {{/each}} -------------------------------------------------------------------------------- /tests/dummy/config/ember-cli-update.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": "1.0.0", 3 | "packages": [ 4 | { 5 | "name": "ember-cli", 6 | "version": "5.0.0", 7 | "blueprints": [ 8 | { 9 | "name": "addon", 10 | "outputRepo": "https://github.com/ember-cli/ember-addon-output", 11 | "codemodsSource": "ember-addon-codemods-manifest@1", 12 | "isBaseBlueprint": true, 13 | "options": [ 14 | "--no-welcome" 15 | ] 16 | } 17 | ] 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /.ember-cli: -------------------------------------------------------------------------------- 1 | { 2 | /** 3 | Ember CLI sends analytics information by default. The data is completely 4 | anonymous, but there are times when you might want to disable this behavior. 5 | 6 | Setting `disableAnalytics` to true will prevent any data from being sent. 7 | */ 8 | "disableAnalytics": false, 9 | 10 | /** 11 | Setting `isTypeScriptProject` to true will force the blueprint generators to generate TypeScript 12 | rather than JavaScript by default, when a TypeScript version of a given blueprint is available. 13 | */ 14 | "isTypeScriptProject": false 15 | } 16 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # compiled output 2 | /dist/ 3 | /tmp/ 4 | 5 | # misc 6 | /.editorconfig 7 | /.ember-cli 8 | /.env* 9 | /.eslintcache 10 | /.eslintignore 11 | /.eslintrc.js 12 | /.git/ 13 | /.github/ 14 | /.gitignore 15 | /.prettierignore 16 | /.prettierrc.js 17 | /.stylelintignore 18 | /.stylelintrc.js 19 | /.template-lintrc.js 20 | /.travis.yml 21 | /.watchmanconfig 22 | /CONTRIBUTING.md 23 | /ember-cli-build.js 24 | /testem.js 25 | /tests/ 26 | /yarn-error.log 27 | /yarn.lock 28 | .gitkeep 29 | 30 | # ember-try 31 | /.node_modules.ember-try/ 32 | /npm-shrinkwrap.json.ember-try 33 | /package.json.ember-try 34 | /package-lock.json.ember-try 35 | /yarn.lock.ember-try 36 | -------------------------------------------------------------------------------- /testem.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | test_page: 'tests/index.html?hidepassed', 5 | disable_watching: true, 6 | launch_in_ci: ['Chrome'], 7 | launch_in_dev: ['Chrome'], 8 | browser_start_timeout: 120, 9 | browser_args: { 10 | Chrome: { 11 | ci: [ 12 | // --no-sandbox is needed when running Chrome inside a container 13 | process.env.CI ? '--no-sandbox' : null, 14 | '--headless', 15 | '--disable-dev-shm-usage', 16 | '--disable-software-rasterizer', 17 | '--mute-audio', 18 | '--remote-debugging-port=0', 19 | '--window-size=1440,900', 20 | ].filter(Boolean), 21 | }, 22 | }, 23 | }; 24 | -------------------------------------------------------------------------------- /tests/dummy/app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Dummy 6 | 7 | 8 | 9 | {{content-for "head"}} 10 | 11 | 12 | 13 | 14 | {{content-for "head-footer"}} 15 | 16 | 17 | {{content-for "body"}} 18 | 19 | 20 | 21 | 22 | {{content-for "body-footer"}} 23 | 24 | 25 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How To Contribute 2 | 3 | ## Installation 4 | 5 | * `git clone ` 6 | * `cd ember-showdown-prism` 7 | * `npm install` 8 | 9 | ## Linting 10 | 11 | * `npm run lint` 12 | * `npm run lint:fix` 13 | 14 | ## Running tests 15 | 16 | * `ember test` – Runs the test suite on the current Ember version 17 | * `ember test --server` – Runs the test suite in "watch mode" 18 | * `ember try:each` – Runs the test suite against multiple Ember versions 19 | 20 | ## Running the dummy application 21 | 22 | * `ember serve` 23 | * Visit the dummy application at [http://localhost:4200](http://localhost:4200). 24 | 25 | For more information on using ember-cli, visit [https://cli.emberjs.com/release/](https://cli.emberjs.com/release/). 26 | -------------------------------------------------------------------------------- /ember-cli-build.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable prettier/prettier */ 2 | 'use strict'; 3 | 4 | const EmberAddon = require('ember-cli/lib/broccoli/ember-addon'); 5 | 6 | module.exports = function (defaults) { 7 | const app = new EmberAddon(defaults, { 8 | prember: { 9 | urls: [ 10 | '/' 11 | ] 12 | } 13 | }); 14 | 15 | /* 16 | This build file specifies the options for the dummy test app of this 17 | addon, located in `/tests/dummy` 18 | This build file does *not* influence how the addon or the app using it 19 | behave. You most likely want to be modifying `./index.js` or app's build file 20 | */ 21 | 22 | const { maybeEmbroider } = require('@embroider/test-setup'); 23 | return maybeEmbroider(app, { 24 | skipBabel: [ 25 | { 26 | package: 'qunit', 27 | }, 28 | ], 29 | }); 30 | }; 31 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2020 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /tests/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Dummy Tests 6 | 7 | 8 | 9 | {{content-for "head"}} 10 | {{content-for "test-head"}} 11 | 12 | 13 | 14 | 15 | 16 | {{content-for "head-footer"}} 17 | {{content-for "test-head-footer"}} 18 | 19 | 20 | {{content-for "body"}} 21 | {{content-for "test-body"}} 22 | 23 |
24 |
25 |
26 |
27 |
28 |
29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | {{content-for "body-footer"}} 37 | {{content-for "test-body-footer"}} 38 | 39 | 40 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable prettier/prettier */ 2 | 'use strict'; 3 | 4 | var Funnel = require('broccoli-funnel'); 5 | const { join } = require('path'); 6 | 7 | module.exports = { 8 | name: require('./package').name, 9 | 10 | treeForPublic: function () { 11 | return new Funnel(join(this.root, 'public')); 12 | }, 13 | 14 | included() { 15 | let app = findHost(this); 16 | if (!app.options['ember-prism']) { 17 | app.options['ember-prism'] = { 18 | theme: 'okaidia', 19 | 20 | components: [ 21 | 'apacheconf', 22 | 'bash', 23 | 'css', 24 | 'http', 25 | 'javascript', 26 | 'json', 27 | 'json5', 28 | 'markup-templating', 29 | 'ruby', 30 | 'scss', 31 | 'yaml', 32 | 'typescript', 33 | 'diff', 34 | ], 35 | plugins: ['line-numbers', 'normalize-whitespace'] 36 | }; 37 | } 38 | 39 | this._super.included.apply(this, arguments); 40 | }, 41 | }; 42 | 43 | // Polyfill [Addon._findHost](https://ember-cli.com/api/classes/Addon.html#method__findHost) for older versions of ember-cli 44 | function findHost(addon) { 45 | var current = addon; 46 | var app; 47 | 48 | do { 49 | app = current.app || app; 50 | } while (current.parent.parent && (current = current.parent)); 51 | 52 | return app; 53 | } 54 | -------------------------------------------------------------------------------- /tests/acceptance/basic-test.js: -------------------------------------------------------------------------------- 1 | import { module, test } from 'qunit'; 2 | import { visit, currentURL } from '@ember/test-helpers'; 3 | import { setupApplicationTest } from 'ember-qunit'; 4 | 5 | module('Acceptance | index', function (hooks) { 6 | setupApplicationTest(hooks); 7 | 8 | test('visiting /', async function (assert) { 9 | await visit('/'); 10 | 11 | assert.strictEqual(currentURL(), '/'); 12 | assert.dom('pre.language-none code.language-none').isVisible(); 13 | assert 14 | .dom('pre.language-none code.language-none') 15 | .hasText('sh go do a thing'); 16 | 17 | assert.dom('pre.language-javascript code.language-javascript').isVisible(); 18 | assert 19 | .dom('pre.language-javascript code.language-javascript') 20 | .hasText(`let thing = 'face'; let myElement = $('.my-element');`); 21 | 22 | assert.dom('div.filename .ribbon').isVisible(); 23 | assert.dom('div.filename span').hasText('app/templates/blog-post.hbs'); 24 | assert.dom('pre.language-handlebars code.language-handlebars').isVisible(); 25 | assert 26 | .dom('pre.language-handlebars code.language-handlebars') 27 | .containsText( 28 | `

{{@model.title}}

by {{@model.author}}

{{ (count @model.posts) }} # posts

{{@model.intro}}

{{@model.body}}
` 29 | ); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | root: true, 5 | parser: '@babel/eslint-parser', 6 | parserOptions: { 7 | ecmaVersion: 'latest', 8 | sourceType: 'module', 9 | requireConfigFile: false, 10 | babelOptions: { 11 | plugins: [ 12 | ['@babel/plugin-proposal-decorators', { decoratorsBeforeExport: true }], 13 | ], 14 | }, 15 | }, 16 | plugins: ['ember'], 17 | extends: [ 18 | 'eslint:recommended', 19 | 'plugin:ember/recommended', 20 | 'plugin:prettier/recommended', 21 | ], 22 | env: { 23 | browser: true, 24 | }, 25 | rules: {}, 26 | overrides: [ 27 | // node files 28 | { 29 | files: [ 30 | './.eslintrc.js', 31 | './.prettierrc.js', 32 | './.stylelintrc.js', 33 | './.template-lintrc.js', 34 | './ember-cli-build.js', 35 | './index.js', 36 | './testem.js', 37 | './blueprints/*/index.js', 38 | './config/**/*.js', 39 | './tests/dummy/config/**/*.js', 40 | ], 41 | parserOptions: { 42 | sourceType: 'script', 43 | }, 44 | env: { 45 | browser: false, 46 | node: true, 47 | }, 48 | extends: ['plugin:n/recommended'], 49 | }, 50 | { 51 | // test files 52 | files: ['tests/**/*-test.{js,ts}'], 53 | extends: ['plugin:qunit/recommended'], 54 | }, 55 | ], 56 | }; 57 | -------------------------------------------------------------------------------- /tests/helpers/index.js: -------------------------------------------------------------------------------- 1 | import { 2 | setupApplicationTest as upstreamSetupApplicationTest, 3 | setupRenderingTest as upstreamSetupRenderingTest, 4 | setupTest as upstreamSetupTest, 5 | } from 'ember-qunit'; 6 | 7 | // This file exists to provide wrappers around ember-qunit's / ember-mocha's 8 | // test setup functions. This way, you can easily extend the setup that is 9 | // needed per test type. 10 | 11 | function setupApplicationTest(hooks, options) { 12 | upstreamSetupApplicationTest(hooks, options); 13 | 14 | // Additional setup for application tests can be done here. 15 | // 16 | // For example, if you need an authenticated session for each 17 | // application test, you could do: 18 | // 19 | // hooks.beforeEach(async function () { 20 | // await authenticateSession(); // ember-simple-auth 21 | // }); 22 | // 23 | // This is also a good place to call test setup functions coming 24 | // from other addons: 25 | // 26 | // setupIntl(hooks); // ember-intl 27 | // setupMirage(hooks); // ember-cli-mirage 28 | } 29 | 30 | function setupRenderingTest(hooks, options) { 31 | upstreamSetupRenderingTest(hooks, options); 32 | 33 | // Additional setup for rendering tests can be done here. 34 | } 35 | 36 | function setupTest(hooks, options) { 37 | upstreamSetupTest(hooks, options); 38 | 39 | // Additional setup for unit tests can be done here. 40 | } 41 | 42 | export { setupApplicationTest, setupRenderingTest, setupTest }; 43 | -------------------------------------------------------------------------------- /public/images/ribbon-ts.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /tests/dummy/config/environment.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable prettier/prettier */ 2 | 'use strict'; 3 | 4 | module.exports = function (environment) { 5 | const ENV = { 6 | modulePrefix: 'dummy', 7 | environment, 8 | rootURL: '/', 9 | locationType: 'history', 10 | EmberENV: { 11 | EXTEND_PROTOTYPES: false, 12 | FEATURES: { 13 | // Here you can enable experimental features on an ember canary build 14 | // e.g. EMBER_NATIVE_DECORATOR_SUPPORT: true 15 | }, 16 | }, 17 | 18 | APP: { 19 | // Here you can pass flags/options to your application instance 20 | // when it is created 21 | }, 22 | fastboot: { 23 | hostWhitelist: [/^localhost:\d+$/] 24 | } 25 | }; 26 | 27 | if (environment === 'development') { 28 | // ENV.APP.LOG_RESOLVER = true; 29 | // ENV.APP.LOG_ACTIVE_GENERATION = true; 30 | // ENV.APP.LOG_TRANSITIONS = true; 31 | // ENV.APP.LOG_TRANSITIONS_INTERNAL = true; 32 | // ENV.APP.LOG_VIEW_LOOKUPS = true; 33 | } 34 | 35 | if (environment === 'test') { 36 | // Testem prefers this... 37 | ENV.locationType = 'none'; 38 | 39 | // keep test console output quieter 40 | ENV.APP.LOG_ACTIVE_GENERATION = false; 41 | ENV.APP.LOG_VIEW_LOOKUPS = false; 42 | 43 | ENV.APP.rootElement = '#ember-testing'; 44 | ENV.APP.autoboot = false; 45 | } 46 | 47 | if (environment === 'production') { 48 | // here you can enable a production-specific feature 49 | } 50 | 51 | return ENV; 52 | }; 53 | -------------------------------------------------------------------------------- /public/images/ribbon-pink.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /public/images/ribbon-purple.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /public/images/ribbon-js.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /public/images/ribbon-hbs.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - master 8 | pull_request: {} 9 | 10 | concurrency: 11 | group: ci-${{ github.head_ref || github.ref }} 12 | cancel-in-progress: true 13 | 14 | jobs: 15 | test: 16 | name: "Tests" 17 | runs-on: ubuntu-latest 18 | timeout-minutes: 10 19 | 20 | steps: 21 | - uses: actions/checkout@v3 22 | - name: Install Node 23 | uses: actions/setup-node@v3 24 | with: 25 | node-version: 16 26 | cache: npm 27 | - name: Install Dependencies 28 | run: npm ci 29 | - name: Lint 30 | run: npm run lint 31 | - name: Run Tests 32 | run: npm run test:ember 33 | 34 | floating: 35 | name: "Floating Dependencies" 36 | runs-on: ubuntu-latest 37 | timeout-minutes: 10 38 | 39 | steps: 40 | - uses: actions/checkout@v3 41 | - uses: actions/setup-node@v3 42 | with: 43 | node-version: 16 44 | cache: npm 45 | - name: Install Dependencies 46 | run: npm install --no-shrinkwrap 47 | - name: Run Tests 48 | run: npm run test:ember 49 | 50 | try-scenarios: 51 | name: ${{ matrix.try-scenario }} 52 | runs-on: ubuntu-latest 53 | needs: "test" 54 | timeout-minutes: 10 55 | 56 | strategy: 57 | fail-fast: false 58 | matrix: 59 | try-scenario: 60 | - ember-lts-3.16 61 | - ember-lts-3.20 62 | - ember-lts-3.24 63 | - ember-lts-3.28 64 | - ember-lts-4.4 65 | - ember-lts-4.8 66 | - ember-lts-4.12 67 | - ember-release 68 | - ember-beta 69 | - ember-canary 70 | - embroider-safe 71 | - embroider-optimized 72 | - ember-release-no-deprecations 73 | - no-deprecations 74 | 75 | steps: 76 | - uses: actions/checkout@v3 77 | - name: Install Node 78 | uses: actions/setup-node@v3 79 | with: 80 | node-version: 16 81 | cache: npm 82 | - name: Install Dependencies 83 | run: npm ci 84 | - name: Run Tests 85 | run: ./node_modules/.bin/ember try:one ${{ matrix.try-scenario }} 86 | -------------------------------------------------------------------------------- /RELEASE.md: -------------------------------------------------------------------------------- 1 | # Release Process 2 | 3 | Releases are mostly automated using 4 | [release-it](https://github.com/release-it/release-it/) and 5 | [lerna-changelog](https://github.com/lerna/lerna-changelog/). 6 | 7 | ## Preparation 8 | 9 | Since the majority of the actual release process is automated, the primary 10 | remaining task prior to releasing is confirming that all pull requests that 11 | have been merged since the last release have been labeled with the appropriate 12 | `lerna-changelog` labels and the titles have been updated to ensure they 13 | represent something that would make sense to our users. Some great information 14 | on why this is important can be found at 15 | [keepachangelog.com](https://keepachangelog.com/en/1.0.0/), but the overall 16 | guiding principle here is that changelogs are for humans, not machines. 17 | 18 | When reviewing merged PR's the labels to be used are: 19 | 20 | * breaking - Used when the PR is considered a breaking change. 21 | * enhancement - Used when the PR adds a new feature or enhancement. 22 | * bug - Used when the PR fixes a bug included in a previous release. 23 | * documentation - Used when the PR adds or updates documentation. 24 | * internal - Used for internal changes that still require a mention in the 25 | changelog/release notes. 26 | 27 | ## Release 28 | 29 | Once the prep work is completed, the actual release is straight forward: 30 | 31 | * First, ensure that you have installed your projects dependencies: 32 | 33 | ```sh 34 | npm install 35 | ``` 36 | 37 | * Second, ensure that you have obtained a 38 | [GitHub personal access token][generate-token] with the `repo` scope (no 39 | other permissions are needed). Make sure the token is available as the 40 | `GITHUB_AUTH` environment variable. 41 | 42 | For instance: 43 | 44 | ```bash 45 | export GITHUB_AUTH=abc123def456 46 | ``` 47 | 48 | [generate-token]: https://github.com/settings/tokens/new?scopes=repo&description=GITHUB_AUTH+env+variable 49 | 50 | * And last (but not least 😁) do your release. 51 | 52 | ```sh 53 | npx release-it 54 | ``` 55 | 56 | [release-it](https://github.com/release-it/release-it/) manages the actual 57 | release process. It will prompt you to to choose the version number after which 58 | you will have the chance to hand tweak the changelog to be used (for the 59 | `CHANGELOG.md` and GitHub release), then `release-it` continues on to tagging, 60 | pushing the tag and commits, etc. 61 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ember-showdown-prism 2 | 3 | ember-showdown-prism is a drop-in addon that automatically adds [Prism](https://prismjs.com/) syntax highlighting to code blocks if you are using [showdown](https://github.com/showdownjs/showdown) to render your Markdown. 4 | 5 | This addon also provides filename wrappers to the code block, with filetype icons, if a code block is marked with a `data-filename` attribute: 6 | 7 | ```markdown 8 | 9 | ````handlebars {data-filename=app/templates/blog-post.hbs} 10 |

{{@model.title}}

11 |

by {{@model.author}}

12 | 13 |
14 | {{@model.intro}} 15 |
16 |
17 |
18 | {{@model.body}} 19 |
20 | ```  21 | ``` 22 | 23 | ![example of the above code sample](https://user-images.githubusercontent.com/594890/91036439-3f524980-e5ff-11ea-910b-b655f036b439.png) 24 | 25 | You will also notice that the code sample has line numbers, this is built-in behaviour and they will be added to all code blocks. The line numbers also have anchors with ids added, which makes them clickable in Fastboot or prember environments. 26 | 27 | This is also specifically designed to work in Node environments so that it can run effectively in Fastboot and prember 🎉 and as it is a drop-in addon it will automatically start working if added to any [Empress](https://github.com/empress) projects, so it can be used to add syntax highlighting to your [empress-blog](https://github.com/empress/empress-blog) if your template doesn't already provide syntax highlighting. 28 | 29 | This addon is building on top of the great work of [ember-cli-showdown](https://github.com/gcollazo/ember-cli-showdown) and [ember-prism](https://github.com/shipshapecode/ember-prism). 30 | 31 | 32 | ## Compatibility 33 | 34 | * Ember.js v3.16 or above 35 | * Ember CLI v3.16 or above 36 | * Node.js v16 or above 37 | 38 | 39 | ## Installation 40 | 41 | ``` 42 | ember install ember-showdown-prism 43 | ``` 44 | 45 | 46 | ## Usage 47 | 48 | Most people don't need to do anything to configure this addon as it comes with a sensible set of default languages that it supports, but if you want to customise the languages that Prism has access to then you can follow the [ember-prism documentation on adding language](https://github.com/shipshapecode/ember-prism#configuration) 49 | 50 | Note: because of the limitations of using Prism in a Node environment you cannot use most prism plugins, essentially you cannot use anything that requires the DOM element while the plugin code is running. 51 | 52 | 53 | ## Contributing 54 | 55 | See the [Contributing](CONTRIBUTING.md) guide for details. 56 | 57 | 58 | ## License 59 | 60 | This project is licensed under the [MIT License](LICENSE.md). 61 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## v4.4.0 (2023-09-29) 4 | 5 | #### :rocket: Enhancement 6 | * [#58](https://github.com/empress/ember-showdown-prism/pull/58) add json5, line-numbers, and normalize-whitespace ([@lupestro](https://github.com/lupestro)) 7 | 8 | #### Committers: 1 9 | - Ralph Mack ([@lupestro](https://github.com/lupestro)) 10 | 11 | ## v4.3.0 (2023-09-29) 12 | 13 | #### :rocket: Enhancement 14 | * [#51](https://github.com/empress/ember-showdown-prism/pull/51) Use the setup function from ember-prism ([@NullVoxPopuli](https://github.com/NullVoxPopuli)) 15 | 16 | #### :bug: Bug Fix 17 | * [#57](https://github.com/empress/ember-showdown-prism/pull/57) Fix data-diff first line bug ([@fry69](https://github.com/fry69)) 18 | 19 | #### Committers: 2 20 | - [@NullVoxPopuli](https://github.com/NullVoxPopuli) 21 | - [@fry69](https://github.com/fry69) 22 | 23 | 4.2.0 / 2023-07-10 24 | ================== 25 | 26 | * add support for data-diff usage in code block #53 from @mansona 27 | 28 | 4.1.0 / 2023-07-03 29 | ================== 30 | 31 | * move ember-prism back to dependencies #49 from @mansona 32 | 33 | 4.0.0 / 2023-07-03 34 | ================== 35 | 36 | * update to v5.0 with ember-cli-update #47 from @mansona 37 | * move showdown to a peer dependency #45 from @mansona 38 | * breaking: drop support for node < 16 #46 from @mansona 39 | 40 | 3.2.0 / 2022-08-06 41 | ================== 42 | * update ember-prism #31 from @mansona 43 | * fix ember-try npm overrides #27 from @mansona 44 | 45 | 3.1.0 / 2022-05-05 46 | ================== 47 | * add typescript and diff components #25 from @mansona 48 | 49 | 3.0.0 / 2021-12-31 50 | ================== 51 | 52 | * update with ember-cli-update to 3.28 #20 from @mansona 53 | * add a basic test #19 from @mansona 54 | * Breaking: drop Node 10 and unify github ci workflow with blueprint #18 from @mansona 55 | 56 | 2.3.0 / 2021-08-12 57 | ================== 58 | 59 | * fix dollar signs in codeblocks breaking when running through Prism #13 from @nickschot 60 | * add a `$` to the demo app to demonstrate the issues with it #14 from @nickschot 61 | * update with ember-cli-update #16 from @mansona 62 | * Move from travis to github actions #15 from @mansona 63 | * add prember for netlify example app #10 from @mansona 64 | * add a better README #9 from @mansona 65 | 66 | 2.2.0 / 2020-08-20 67 | ================== 68 | 69 | * add linkable line numbers to highlighted code blocks #8 from @nickschot 70 | 71 | 2.1.0 / 2020-08-19 72 | ================== 73 | 74 | * add assertion if missing language is used & fallback to non-prism rendering #5 from @nickschot 75 | * add YAML to the default enabled languages #6 from @nickschot 76 | 77 | 2.0.0 / 2020-08-17 78 | ================== 79 | 80 | This is only a breaking change because it dropped support for Node 8 and Ember < 3.12. They will likely continue to work for a little while but we are no longer testing them 👍 81 | 82 | * use findHost to find the app (fixes non-working prism when using this addon indirectly) #4 from @nickschot 83 | * Breaking: Update dependencies #2 from @mansona 84 | -------------------------------------------------------------------------------- /addon/styles/addon.css: -------------------------------------------------------------------------------- 1 | div.filename { 2 | background-color: #292929; 3 | } 4 | 5 | pre[class*="language-"] { 6 | background-color: #151515; 7 | } 8 | 9 | .filename { 10 | border-radius: 0.3em; 11 | } 12 | 13 | .ribbon { 14 | margin-top: 0.33em; 15 | float: right; 16 | height: 20px; 17 | width: 52px; 18 | background: 0 0 no-repeat; 19 | background-size: 52px 20px; 20 | } 21 | 22 | .filename > span { 23 | font-family: Menlo, "DejaVu Sans Mono", "Bitstream Vera Sans Mono", Courier, 24 | monospace; 25 | font-size: 0.8em; 26 | color: lightgrey; 27 | display: block; 28 | padding: 5px 0 0 10px; 29 | } 30 | 31 | .filename.javascript .ribbon, 32 | .filename.js .ribbon { 33 | background-image: url("/images/ribbon-js.svg"); 34 | } 35 | 36 | .filename.html .ribbon { 37 | background-image: url("/images/ribbon-html.svg"); 38 | } 39 | 40 | .filename.handlebars .ribbon, 41 | .filename.hbs .ribbon { 42 | background-image: url("/images/ribbon-hbs.svg"); 43 | } 44 | 45 | .filename.typescript .ribbon, 46 | .filename.ts .ribbon { 47 | background-image: url("/images/ribbon-ts.svg"); 48 | } 49 | 50 | code { 51 | font-feature-settings: "kern", "tnum"; 52 | } 53 | 54 | pre[class*="language-"].line-numbers { 55 | position: relative; 56 | padding-left: 3.8em; 57 | counter-reset: linenumber; 58 | } 59 | 60 | pre[class*="language-"].line-numbers > code { 61 | position: relative; 62 | white-space: inherit; 63 | } 64 | 65 | .line-numbers .line-numbers-rows { 66 | position: absolute; 67 | top: 0; 68 | font-size: 100%; 69 | left: -3.8em; 70 | width: 3em; /* works for line-numbers below 1000 lines */ 71 | letter-spacing: -1px; 72 | border-right: 1px solid #999; 73 | } 74 | 75 | .line-numbers-rows > a { 76 | display: block; 77 | counter-increment: linenumber; 78 | background: none !important; 79 | text-decoration: none !important; 80 | } 81 | 82 | .line-numbers-rows > a::before { 83 | content: counter(linenumber); 84 | color: #999; 85 | display: block; 86 | padding-right: 0.8em; 87 | text-align: right; 88 | } 89 | 90 | .line-numbers-rows > a:hover::before, 91 | .line-numbers-rows > a:focus::before { 92 | color: #fff; 93 | } 94 | 95 | .token.regex, 96 | .token.important, 97 | .token.variable { 98 | color: #c3f590; 99 | } 100 | 101 | code > .token.property, 102 | code > .token.tag, 103 | code > .token.constant, 104 | code > .token.symbol, 105 | code > .token.deleted { 106 | color: #ff6fa3; 107 | } 108 | 109 | code > .diff-insertion { 110 | background-color: rgb(93 125 93 / 50%); 111 | 112 | .token.property, 113 | .token.tag, 114 | .token.constant, 115 | .token.symbol, 116 | .token.deleted { 117 | color: #ff95bb; 118 | } 119 | } 120 | 121 | code > .diff-deletion { 122 | background-color: rgb(144 84 84 / 70%); 123 | 124 | .token.property, 125 | .token.tag, 126 | .token.constant, 127 | .token.symbol, 128 | .token.deleted { 129 | color: #ffaac8; 130 | } 131 | } 132 | 133 | /* don't include "removed" code when copy-pasting diffs */ 134 | code .diff-operator, 135 | code .diff-deletion { 136 | user-select: none; 137 | } 138 | 139 | code .token.comment { 140 | color: #e6e6e6; 141 | } 142 | -------------------------------------------------------------------------------- /tests/dummy/public/example.md: -------------------------------------------------------------------------------- 1 | Start with something simple 2 | 3 | This is an inline code example `sh go do a thing`. 4 | 5 | Let's make it a block 6 | ``` 7 | sh go do a thing 8 | ``` 9 | 10 | Adding a `javascript` as a language to get syntax highlighting 11 | ```javascript 12 | let thing = 'face'; 13 | let myElement = $('.my-element'); 14 | ``` 15 | 16 | Now let's do something a bit more complex 17 | 18 | ```handlebars {data-filename=app/templates/blog-post.hbs} 19 |

{{@model.title}}

20 |

by {{@model.author}}

21 |

{{ (count @model.posts) }} # posts

22 | 23 |
24 | {{@model.intro}} 25 |
26 |
27 |
28 | {{@model.body}} 29 |
30 | 31 | 48 | <:block as |foo baz|> 49 | {{foo}} 50 | 51 | {{#let foo.bar 12 as |fooBar num|}} 52 | 53 | {{/let}} 54 | 55 | {{! comment }} 56 | {{!-- block }} 57 | TODO: Indentation is broken after that 58 | comment --}} 59 | 60 | 61 | 62 | 63 | ``` 64 | 65 | With some different file types 66 | 67 | ```javascript {data-filename=app/controllers/blog-post.js} 68 | import Controller from '@ember/controller'; 69 | import { action } from '@ember/object'; 70 | 71 | export default class BlogPostController extends Controller { 72 | isExpanded = false 73 | 74 | @action 75 | toggleBody() { 76 | this.toggleProperty('isExpanded'); 77 | } 78 | } 79 | ``` 80 | 81 | Typescript never hurts 82 | 83 | ```typescript {data-filename=app/router.ts} 84 | import EmberRouter from '@ember/routing/router'; 85 | import config from './config/environment'; 86 | 87 | export default class Router extends EmberRouter { 88 | location = config.locationType; 89 | rootURL = config.rootURL; 90 | } 91 | 92 | Router.map(function() {}); 93 | ``` 94 | 95 | With a diff: 96 | 97 | ```javascript {data-filename="app/router.js" data-diff="+10,-11"} 98 | import EmberRouter from '@ember/routing/router'; 99 | import config from './config/environment'; 100 | 101 | const Router = EmberRouter.extend({ 102 | location: config.locationType, 103 | rootURL: config.rootURL 104 | }); 105 | 106 | Router.map(function() { 107 | this.route('about'); 108 | this.route('face'); 109 | }); 110 | 111 | export default Router; 112 | ``` 113 | 114 | With a diff on the first line: 115 | 116 | ```javascript {data-filename="app/router.js" data-diff="-1,+2"} 117 | import EmberRouter from '@ember/routing/router'; 118 | import EmberRouter from '@embroider/router'; 119 | import config from './config/environment'; 120 | 121 | const Router = EmberRouter.extend({ 122 | location: config.locationType, 123 | rootURL: config.rootURL 124 | }); 125 | 126 | Router.map(function() { 127 | this.route('about'); 128 | }); 129 | 130 | export default Router; 131 | ``` 132 | -------------------------------------------------------------------------------- /tests/dummy/config/ember-try.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable prettier/prettier */ 2 | 'use strict'; 3 | 4 | const getChannelURL = require('ember-source-channel-url'); 5 | const { embroiderSafe, embroiderOptimized } = require('@embroider/test-setup'); 6 | 7 | module.exports = async function () { 8 | return { 9 | scenarios: [ 10 | { 11 | name: 'ember-lts-3.16', 12 | npm: { 13 | devDependencies: { 14 | 'ember-cli': '^4.0.0', 15 | 'ember-source': '~3.16.0', 16 | 'ember-qunit': '6.0.0', 17 | 'ember-resolver': '^8.0.0', 18 | '@ember/test-helpers': '^2.9.0', 19 | } 20 | } 21 | }, 22 | { 23 | name: 'ember-lts-3.20', 24 | npm: { 25 | devDependencies: { 26 | 'ember-cli': '^4.0.0', 27 | 'ember-source': '~3.20.5', 28 | 'ember-qunit': '6.0.0', 29 | 'ember-resolver': '^8.0.0', 30 | '@ember/test-helpers': '^2.9.0', 31 | }, 32 | }, 33 | }, 34 | { 35 | name: 'ember-lts-3.24', 36 | npm: { 37 | devDependencies: { 38 | 'ember-cli': '^4.0.0', 39 | 'ember-source': '~3.24.3', 40 | 'ember-qunit': '6.0.0', 41 | 'ember-resolver': '^8.0.0', 42 | '@ember/test-helpers': '^2.9.0', 43 | }, 44 | }, 45 | }, 46 | { 47 | name: 'ember-lts-3.28', 48 | npm: { 49 | devDependencies: { 50 | 'ember-cli': '^4.0.0', 51 | 'ember-source': '~3.28.0', 52 | 'ember-qunit': '^6.2.0', 53 | 'ember-resolver': '^8.0.0', 54 | '@ember/test-helpers': '^2.9.0', 55 | }, 56 | }, 57 | }, 58 | { 59 | name: 'ember-lts-4.4', 60 | npm: { 61 | devDependencies: { 62 | 'ember-source': '~4.4.0', 63 | 'ember-resolver': '^8.0.0', 64 | }, 65 | }, 66 | }, 67 | { 68 | name: 'ember-lts-4.8', 69 | npm: { 70 | devDependencies: { 71 | 'ember-source': '~4.8.0', 72 | }, 73 | }, 74 | }, 75 | { 76 | name: 'ember-lts-4.12', 77 | npm: { 78 | devDependencies: { 79 | 'ember-source': '~4.12.0', 80 | }, 81 | }, 82 | }, 83 | { 84 | name: 'ember-release', 85 | npm: { 86 | devDependencies: { 87 | 'ember-source': await getChannelURL('release'), 88 | }, 89 | overrides: { 90 | 'ember-source': '$ember-source', 91 | }, 92 | }, 93 | }, 94 | { 95 | name: 'ember-beta', 96 | npm: { 97 | devDependencies: { 98 | 'ember-source': await getChannelURL('beta'), 99 | }, 100 | overrides: { 101 | 'ember-source': '$ember-source', 102 | }, 103 | }, 104 | }, 105 | { 106 | name: 'ember-canary', 107 | npm: { 108 | devDependencies: { 109 | 'ember-source': await getChannelURL('canary'), 110 | }, 111 | overrides: { 112 | 'ember-source': '$ember-source', 113 | }, 114 | }, 115 | }, 116 | embroiderSafe(), 117 | embroiderOptimized(), 118 | { 119 | name: 'no-deprecations', 120 | npm: { 121 | devDependencies: { 122 | 'ember-deprecation-error': '*', 123 | }, 124 | }, 125 | }, 126 | { 127 | name: 'ember-release-no-deprecations', 128 | npm: { 129 | devDependencies: { 130 | 'ember-source': await getChannelURL('release'), 131 | 'ember-deprecation-error': '*', 132 | }, 133 | overrides: { 134 | 'ember-source': '$ember-source', 135 | }, 136 | }, 137 | }, 138 | ], 139 | }; 140 | }; 141 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ember-showdown-prism", 3 | "version": "4.4.0", 4 | "description": "The default blueprint for ember-cli addons.", 5 | "keywords": [ 6 | "ember-addon" 7 | ], 8 | "repository": "https://github.com/empress/ember-showdown-prism", 9 | "license": "MIT", 10 | "author": "", 11 | "directories": { 12 | "doc": "doc", 13 | "test": "tests" 14 | }, 15 | "scripts": { 16 | "build": "ember build --environment=production", 17 | "ember-compatibility-test": "ember try:each", 18 | "lint": "concurrently \"npm:lint:*(!fix)\" --names \"lint:\"", 19 | "lint:css": "stylelint \"**/*.css\"", 20 | "lint:css:fix": "concurrently \"npm:lint:css -- --fix\"", 21 | "lint:fix": "concurrently \"npm:lint:*:fix\" --names \"fix:\"", 22 | "lint:hbs": "ember-template-lint .", 23 | "lint:hbs:fix": "ember-template-lint . --fix", 24 | "lint:js": "eslint . --cache", 25 | "lint:js:fix": "eslint . --fix", 26 | "start": "ember serve", 27 | "test": "concurrently \"npm:lint\" \"npm:test:*\" --names \"lint,test:\"", 28 | "test:ember": "ember test" 29 | }, 30 | "dependencies": { 31 | "broccoli-funnel": "^3.0.1", 32 | "ember-auto-import": "^2.6.3", 33 | "ember-cli-babel": "^7.26.11", 34 | "ember-prism": "^0.13.0" 35 | }, 36 | "devDependencies": { 37 | "@babel/eslint-parser": "^7.22.5", 38 | "@babel/plugin-proposal-decorators": "^7.22.5", 39 | "@ember/optional-features": "^2.0.0", 40 | "@ember/string": "^3.1.1", 41 | "@ember/test-helpers": "^3.0.3", 42 | "@embroider/test-setup": "^3.0.1", 43 | "@glimmer/component": "^1.1.2", 44 | "@glimmer/tracking": "^1.1.2", 45 | "@release-it-plugins/lerna-changelog": "^5.0.0", 46 | "broccoli-asset-rev": "^3.0.0", 47 | "concurrently": "^8.2.0", 48 | "ember-cli": "~5.0.0", 49 | "ember-cli-clean-css": "^2.0.0", 50 | "ember-cli-dependency-checker": "^3.3.1", 51 | "ember-cli-fastboot": "^4.1.1", 52 | "ember-cli-htmlbars": "^6.2.0", 53 | "ember-cli-inject-live-reload": "^2.1.0", 54 | "ember-cli-showdown": "^7.0.0", 55 | "ember-cli-sri": "^2.1.1", 56 | "ember-cli-terser": "^4.0.2", 57 | "ember-fetch": "^8.1.1", 58 | "ember-load-initializers": "^2.1.2", 59 | "ember-page-title": "^7.0.0", 60 | "ember-qunit": "^7.0.0", 61 | "ember-resolver": "^10.1.0", 62 | "ember-source": "~5.0.0", 63 | "ember-source-channel-url": "^3.0.0", 64 | "ember-template-lint": "^5.10.1", 65 | "ember-try": "github:ember-cli/ember-try", 66 | "eslint": "^8.42.0", 67 | "eslint-config-prettier": "^8.8.0", 68 | "eslint-plugin-ember": "^11.8.0", 69 | "eslint-plugin-n": "^16.0.0", 70 | "eslint-plugin-prettier": "^4.2.1", 71 | "eslint-plugin-qunit": "^7.3.4", 72 | "lint-to-the-future": "^2.0.0", 73 | "lint-to-the-future-eslint": "^2.0.1", 74 | "loader.js": "^4.7.0", 75 | "prember": "^2.0.0", 76 | "prettier": "^2.8.8", 77 | "qunit": "^2.19.4", 78 | "qunit-dom": "^2.0.0", 79 | "release-it": "^15.5.0", 80 | "showdown": "^1.9.1", 81 | "stylelint": "^15.7.0", 82 | "stylelint-config-standard": "^33.0.0", 83 | "stylelint-prettier": "^3.0.0", 84 | "webpack": "^5.86.0" 85 | }, 86 | "peerDependencies": { 87 | "ember-source": "^3.16.0 || >= 4.0.0", 88 | "showdown": ">1.0.0" 89 | }, 90 | "engines": { 91 | "node": "16.* || >= 18" 92 | }, 93 | "publishConfig": { 94 | "registry": "https://registry.npmjs.org" 95 | }, 96 | "ember": { 97 | "edition": "octane" 98 | }, 99 | "ember-addon": { 100 | "configPath": "tests/dummy/config" 101 | }, 102 | "release-it": { 103 | "plugins": { 104 | "@release-it-plugins/lerna-changelog": { 105 | "infile": "CHANGELOG.md", 106 | "launchEditor": true 107 | } 108 | }, 109 | "git": { 110 | "tagName": "v${version}" 111 | }, 112 | "github": { 113 | "release": true, 114 | "tokenRef": "GITHUB_AUTH" 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /addon/initializers/showdown-extension.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable prettier/prettier */ 2 | /* global Prism */ 3 | import showdown from 'showdown'; 4 | import { assert } from '@ember/debug'; 5 | 6 | import { setup } from 'ember-prism'; 7 | 8 | setup(); 9 | 10 | // taken from prismjs, regex to detect newlines in text 11 | const NEW_LINE_EXP = /\n(?!$)/g; 12 | 13 | function getLineNumbersHTML(index, codeblock) { 14 | let match = codeblock.match(NEW_LINE_EXP); 15 | let linesNum = match ? match.length + 1 : 1; 16 | let lines = ''; 17 | for (let i = 1; i < linesNum + 1; i++) { 18 | let id = `C${index}_L${i}`; 19 | lines += `` 20 | } 21 | 22 | return ``; 23 | } 24 | 25 | function stripQuotes(string) { 26 | if(string?.startsWith('"') && string?.endsWith('"')) { 27 | return string.substring(1, string.length - 1); 28 | } 29 | return string; 30 | } 31 | 32 | function diffInfo(args, codeblock) { 33 | if (args) { 34 | let lines = codeblock.split('\n'); 35 | 36 | args.forEach(pD => { 37 | let operator = pD[0]; 38 | let lineNo = +(pD.replace(operator, '')); 39 | let text = lines[lineNo - 1]; 40 | if (operator === '+') { 41 | lines[lineNo - 1] = `+${text}`; 42 | } else { 43 | lines[lineNo - 1] = `-${text}`; 44 | } 45 | }); 46 | codeblock = lines.join('\n'); 47 | } 48 | return codeblock; 49 | } 50 | 51 | export function initialize(/* application */) { 52 | showdown.subParser('githubCodeBlocks', function (text, options, globals) { 53 | // early exit if option is not enabled 54 | if (!options.ghCodeBlocks) { 55 | return text; 56 | } 57 | 58 | text = globals.converter._dispatch('githubCodeBlocks.before', text, options, globals); 59 | 60 | text += '¨0'; 61 | 62 | let idCounter = 1; 63 | text = text.replace(/(?:^|\n)(?: {0,3})(```+|~~~+)(?: *)([^\n`~]*)\n([\s\S]*?)\n(?: {0,3})\1/g, function (wholeMatch, delim, languageBlock, inputCodeblock) { 64 | var end = (options.omitExtraWLInCodeBlocks) ? '' : '\n'; 65 | 66 | let codeblock = inputCodeblock; 67 | 68 | // First parse the github code block 69 | // codeblock = showdown.subParser('encodeCode')(codeblock, options, globals); 70 | codeblock = showdown.subParser('detab')(codeblock, options, globals); 71 | codeblock = codeblock.replace(/^\n+/g, ''); // trim leading newlines 72 | codeblock = codeblock.replace(/\n+$/g, ''); // trim trailing whitespace 73 | 74 | let match = languageBlock.match(/(\w+) ?(\{([^}]*)\})?/); 75 | let language = ''; 76 | let attributeString = ''; 77 | 78 | if(match && match[1]) { 79 | language = match[1]; 80 | } 81 | 82 | if (match && match[3]) { 83 | attributeString = match[3]; 84 | } 85 | 86 | let attributes = {}; 87 | 88 | attributeString.split(' ').forEach(attribute => { 89 | let keyValue = attribute.split('='); 90 | attributes[keyValue[0]] = stripQuotes(keyValue[1]); 91 | }); 92 | 93 | let lineNumbersHTML = getLineNumbersHTML(idCounter, codeblock); 94 | idCounter++; 95 | 96 | let diffInfoArgs = attributes['data-diff']?.split(','); 97 | 98 | assert(`Language "${language}" not found. Have you configured Prism correctly?`, !language || Prism.languages[language]); 99 | 100 | if (language && Prism.languages[language]) { 101 | // Restore dollar signs & tremas temporarily so Prism won't highlight this 102 | // See https://github.com/showdownjs/showdown/blob/a9f38b6f057284460d6447371f3dc5dea999c0a6/src/converter.js#L285 for more info 103 | codeblock = codeblock.replace(/¨D/g, '$$'); 104 | codeblock = codeblock.replace(/¨T/g, '¨'); 105 | 106 | let highlightedCodeBlock = Prism.highlight(codeblock, Prism.languages[language], language) + end; 107 | highlightedCodeBlock = diffInfo(diffInfoArgs, highlightedCodeBlock); 108 | codeblock = `
${highlightedCodeBlock}${lineNumbersHTML}
`; 109 | 110 | // Convert to the special characters Showdown uses again 111 | codeblock = codeblock.replace(/¨/g, '¨T'); 112 | codeblock = codeblock.replace(/\$/g, '¨D'); 113 | 114 | if(attributes['data-filename']) { 115 | codeblock = `
${attributes['data-filename'] || ''}${codeblock}
`; 116 | } 117 | } else { 118 | codeblock = diffInfo(diffInfoArgs, codeblock); 119 | codeblock = `
${codeblock}${lineNumbersHTML}
`; 120 | } 121 | 122 | codeblock = showdown.subParser('hashBlock')(codeblock, options, globals); 123 | 124 | // Since GHCodeblocks can be false positives, we need to 125 | // store the primitive text and the parsed text in a global var, 126 | // and then return a token 127 | return '\n\n¨G' + (globals.ghCodeBlocks.push({text: wholeMatch, codeblock: codeblock}) - 1) + 'G\n\n'; 128 | }); 129 | 130 | // attacklab: strip sentinel 131 | text = text.replace(/¨0/, ''); 132 | 133 | return globals.converter._dispatch('githubCodeBlocks.after', text, options, globals); 134 | }); 135 | } 136 | 137 | export default { 138 | initialize 139 | }; 140 | --------------------------------------------------------------------------------