diff --git a/.gitignore b/.gitignore index 15c4d8e..9f1e25f 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ node_modules/ *.d.ts *.log .DS_Store +package-lock.json yarn.lock diff --git a/.npmrc b/.npmrc deleted file mode 100644 index 43c97e7..0000000 --- a/.npmrc +++ /dev/null @@ -1 +0,0 @@ -package-lock=false diff --git a/lib/core.js b/lib/core.js index 95c45e4..2368799 100644 --- a/lib/core.js +++ b/lib/core.js @@ -32,46 +32,11 @@ * @property {Languages} languages */ -/* eslint-disable no-undef */ -// Don’t allow Prism to run on page load in browser or to start messaging from -// workers. -/* c8 ignore next 15 */ -/** @type {typeof globalThis} */ -const ctx = - typeof globalThis === 'object' - ? globalThis - : // @ts-expect-error - typeof self === 'object' - ? // @ts-expect-error - self - : // @ts-expect-error - typeof window === 'object' - ? // @ts-expect-error - window - : typeof global === 'object' - ? global - : {} -/* eslint-enable no-undef */ - -const restore = capture() - -/* c8 ignore next 5 */ -ctx.Prism = ctx.Prism || {} -ctx.Prism.manual = true -ctx.Prism.disableWorkerMessageHandler = true - -/* eslint-disable import/first */ - // Load all stuff in `prism.js` itself, except for `prism-file-highlight.js`. // The wrapped non-leaky grammars are loaded instead of Prism’s originals. import {h} from 'hastscript' import {parseEntities} from 'parse-entities' -// @ts-expect-error: untyped. -import Prism from 'prismjs/components/prism-core.js' - -/* eslint-enable import/first */ - -restore() +import {Prism} from './prism-core.js' const own = {}.hasOwnProperty @@ -137,6 +102,7 @@ function highlight(value, language) { return { type: 'root', + // @ts-expect-error: we hacked Prism to accept and return the things we want. children: Prism.highlight.call(refractor, value, grammar, name) } } @@ -317,33 +283,3 @@ function attributes(attrs) { return attrs } - -/** - * @returns {() => void} - */ -function capture() { - /** @type {boolean|undefined} */ - let defined = 'Prism' in ctx - /* c8 ignore next */ - let current = defined ? ctx.Prism : undefined - - return restore - - /** - * @returns {void} - */ - function restore() { - /* istanbul ignore else - Clean leaks after Prism. */ - if (defined) { - // @ts-expect-error: hush. - ctx.Prism = current - /* c8 ignore next 4 */ - } else { - // @ts-expect-error: hush. - delete ctx.Prism - } - - defined = undefined - current = undefined - } -} diff --git a/lib/prism-core.js b/lib/prism-core.js new file mode 100644 index 0000000..a1cce97 --- /dev/null +++ b/lib/prism-core.js @@ -0,0 +1,818 @@ +// @ts-nocheck + +// This is a slimmed down version of `prism-core.js`, to remove globals, +// document, workers, `util.encode`, `Token.stringify` + +// Private helper vars +var lang = /(?:^|\s)lang(?:uage)?-([\w-]+)(?=\s|$)/i +var uniqueId = 0 + +// The grammar object for plaintext +var plainTextGrammar = {} + +var _ = { + /** + * A namespace for utility methods. + * + * All function in this namespace that are not explicitly marked as _public_ are for __internal use only__ and may + * change or disappear at any time. + * + * @namespace + * @memberof Prism + */ + util: { + /** + * Returns the name of the type of the given value. + * + * @param {any} o + * @returns {string} + * @example + * type(null) === 'Null' + * type(undefined) === 'Undefined' + * type(123) === 'Number' + * type('foo') === 'String' + * type(true) === 'Boolean' + * type([1, 2]) === 'Array' + * type({}) === 'Object' + * type(String) === 'Function' + * type(/abc+/) === 'RegExp' + */ + type: function (o) { + return Object.prototype.toString.call(o).slice(8, -1) + }, + + /** + * Returns a unique number for the given object. Later calls will still return the same number. + * + * @param {Object} obj + * @returns {number} + */ + objId: function (obj) { + if (!obj['__id']) { + Object.defineProperty(obj, '__id', {value: ++uniqueId}) + } + return obj['__id'] + }, + + /** + * Creates a deep clone of the given object. + * + * The main intended use of this function is to clone language definitions. + * + * @param {T} o + * @param {Record} [visited] + * @returns {T} + * @template T + */ + clone: function deepClone(o, visited) { + visited = visited || {} + + var clone + var id + switch (_.util.type(o)) { + case 'Object': + id = _.util.objId(o) + if (visited[id]) { + return visited[id] + } + clone = /** @type {Record} */ ({}) + visited[id] = clone + + for (var key in o) { + if (o.hasOwnProperty(key)) { + clone[key] = deepClone(o[key], visited) + } + } + + return /** @type {any} */ (clone) + + case 'Array': + id = _.util.objId(o) + if (visited[id]) { + return visited[id] + } + clone = [] + visited[id] = clone + + ;/** @type {Array} */ (/** @type {any} */ (o)).forEach(function ( + v, + i + ) { + clone[i] = deepClone(v, visited) + }) + + return /** @type {any} */ (clone) + + default: + return o + } + } + }, + + /** + * This namespace contains all currently loaded languages and the some helper functions to create and modify languages. + * + * @namespace + * @memberof Prism + * @public + */ + languages: { + /** + * The grammar for plain, unformatted text. + */ + plain: plainTextGrammar, + plaintext: plainTextGrammar, + text: plainTextGrammar, + txt: plainTextGrammar, + + /** + * Creates a deep copy of the language with the given id and appends the given tokens. + * + * If a token in `redef` also appears in the copied language, then the existing token in the copied language + * will be overwritten at its original position. + * + * ## Best practices + * + * Since the position of overwriting tokens (token in `redef` that overwrite tokens in the copied language) + * doesn't matter, they can technically be in any order. However, this can be confusing to others that trying to + * understand the language definition because, normally, the order of tokens matters in Prism grammars. + * + * Therefore, it is encouraged to order overwriting tokens according to the positions of the overwritten tokens. + * Furthermore, all non-overwriting tokens should be placed after the overwriting ones. + * + * @param {string} id The id of the language to extend. This has to be a key in `Prism.languages`. + * @param {Grammar} redef The new tokens to append. + * @returns {Grammar} The new language created. + * @public + * @example + * Prism.languages['css-with-colors'] = Prism.languages.extend('css', { + * // Prism.languages.css already has a 'comment' token, so this token will overwrite CSS' 'comment' token + * // at its original position + * 'comment': { ... }, + * // CSS doesn't have a 'color' token, so this token will be appended + * 'color': /\b(?:red|green|blue)\b/ + * }); + */ + extend: function (id, redef) { + var lang = _.util.clone(_.languages[id]) + + for (var key in redef) { + lang[key] = redef[key] + } + + return lang + }, + + /** + * Inserts tokens _before_ another token in a language definition or any other grammar. + * + * ## Usage + * + * This helper method makes it easy to modify existing languages. For example, the CSS language definition + * not only defines CSS highlighting for CSS documents, but also needs to define highlighting for CSS embedded + * in HTML through `