Add, configure and run pre-commit locally and in test workflow

This commit is contained in:
Debanjum Singh Solanky 2023-02-17 12:07:59 -06:00
parent 5e83baab21
commit 051f0e3fb5
22 changed files with 183 additions and 162 deletions

View file

@ -44,4 +44,4 @@ jobs:
push: true push: true
tags: ghcr.io/${{ github.repository }}:${{ env.DOCKER_IMAGE_TAG }} tags: ghcr.io/${{ github.repository }}:${{ env.DOCKER_IMAGE_TAG }}
build-args: | build-args: |
PORT=8000 PORT=8000

View file

@ -78,4 +78,4 @@ jobs:
uses: pypa/gh-action-pypi-publish@v1.6.4 uses: pypa/gh-action-pypi-publish@v1.6.4
with: with:
password: ${{ secrets.PYPI_API_KEY }} password: ${{ secrets.PYPI_API_KEY }}
repository_url: https://test.pypi.org/legacy/ repository_url: https://test.pypi.org/legacy/

View file

@ -9,6 +9,7 @@ on:
- tests/** - tests/**
- config/** - config/**
- pyproject.toml - pyproject.toml
- .pre-commit-config.yml
- .github/workflows/test.yml - .github/workflows/test.yml
push: push:
branches: branches:
@ -18,6 +19,7 @@ on:
- tests/** - tests/**
- config/** - config/**
- pyproject.toml - pyproject.toml
- .pre-commit-config.yml
- .github/workflows/test.yml - .github/workflows/test.yml
jobs: jobs:
@ -45,9 +47,10 @@ jobs:
python -m pip install --upgrade pip python -m pip install --upgrade pip
- name: Install Application - name: Install Application
run: | run: pip install --upgrade .[dev]
pip install --upgrade .[dev]
- name: Validate Application
run: pre-commit
- name: Test Application - name: Test Application
run: | run: pytest
pytest

16
.pre-commit-config.yaml Normal file
View file

@ -0,0 +1,16 @@
repos:
- repo: https://github.com/psf/black
rev: 23.1.0
hooks:
- id: black
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.3.0
hooks:
- id: end-of-file-fixer
- id: trailing-whitespace
# Exclude elisp files to not clear page breaks
exclude: \.el$
- id: check-json
- id: check-toml
- id: check-yaml

View file

@ -4,4 +4,4 @@ Name=Khoj
Comment=A natural language search engine for your personal notes, transactions and images. Comment=A natural language search engine for your personal notes, transactions and images.
Path=/opt Path=/opt
Exec=/opt/Khoj Exec=/opt/Khoj
Icon=Khoj Icon=Khoj

View file

@ -619,4 +619,3 @@ Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee. copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS END OF TERMS AND CONDITIONS

View file

@ -19,4 +19,4 @@ dependencies:
- aiofiles=0.8.0 - aiofiles=0.8.0
- huggingface_hub=0.8.1 - huggingface_hub=0.8.1
- dateparser=1.1.1 - dateparser=1.1.1
- schedule=1.1.0 - schedule=1.1.0

View file

@ -52,4 +52,4 @@ processor:
#conversation: #conversation:
# openai-api-key: null # openai-api-key: null
# model: "text-davinci-003" # model: "text-davinci-003"
# conversation-logfile: "/data/embeddings/conversation_logs.json" # conversation-logfile: "/data/embeddings/conversation_logs.json"

View file

@ -4,14 +4,14 @@ services:
image: ghcr.io/debanjum/khoj:latest image: ghcr.io/debanjum/khoj:latest
ports: ports:
# If changing the local port (left hand side), no other changes required. # If changing the local port (left hand side), no other changes required.
# If changing the remote port (right hand side), # If changing the remote port (right hand side),
# change the port in the args in the build section, # change the port in the args in the build section,
# as well as the port in the command section to match # as well as the port in the command section to match
- "8000:8000" - "8000:8000"
working_dir: /app working_dir: /app
volumes: volumes:
- .:/app - .:/app
# These mounted volumes hold the raw data that should be indexed for search. # These mounted volumes hold the raw data that should be indexed for search.
# The path in your local directory (left hand side) # The path in your local directory (left hand side)
# points to the files you want to index. # points to the files you want to index.
# The path of the mounted directory (right hand side), # The path of the mounted directory (right hand side),

View file

@ -64,10 +64,14 @@ khoj = "khoj.main:run"
[project.optional-dependencies] [project.optional-dependencies]
test = [ test = [
"pytest >= 7.1.2", "pytest >= 7.1.2",
"black >= 23.1.0", ]
dev = [
"khoj-assistant[test]",
"mypy >= 1.0.1",
"black >= 23.1.0",
"pre-commit >= 3.0.4",
] ]
dev = ["khoj-assistant[test]"]
[tool.hatch.build.targets.sdist] [tool.hatch.build.targets.sdist]
include = ["src/khoj"] include = ["src/khoj"]
@ -79,8 +83,8 @@ packages = ["src/khoj"]
files = "src/khoj" files = "src/khoj"
pretty = true pretty = true
strict_optional = false strict_optional = false
ignore_missing_imports = true
install_types = true install_types = true
ignore_missing_imports = true
non_interactive = true non_interactive = true
show_error_codes = true show_error_codes = true
warn_unused_ignores = true warn_unused_ignores = true
@ -91,4 +95,4 @@ exclude = [
] ]
[tool.black] [tool.black]
line-length = 120 line-length = 120

View file

@ -1,6 +1,6 @@
* Khoj Emacs 🦅 * Khoj Emacs 🦅
[[https://stable.melpa.org/#/khoj][file:https://stable.melpa.org/packages/khoj-badge.svg]] [[https://melpa.org/#/khoj][file:https://melpa.org/packages/khoj-badge.svg]] [[https://github.com/debanjum/khoj/actions/workflows/build_khoj_el.yml][https://github.com/debanjum/khoj/actions/workflows/build_khoj_el.yml/badge.svg?]] [[https://github.com/debanjum/khoj/actions/workflows/test_khoj_el.yml][https://github.com/debanjum/khoj/actions/workflows/test_khoj_el.yml/badge.svg?]] [[https://stable.melpa.org/#/khoj][file:https://stable.melpa.org/packages/khoj-badge.svg]] [[https://melpa.org/#/khoj][file:https://melpa.org/packages/khoj-badge.svg]] [[https://github.com/debanjum/khoj/actions/workflows/build_khoj_el.yml][https://github.com/debanjum/khoj/actions/workflows/build_khoj_el.yml/badge.svg?]] [[https://github.com/debanjum/khoj/actions/workflows/test_khoj_el.yml][https://github.com/debanjum/khoj/actions/workflows/test_khoj_el.yml/badge.svg?]]
/Natural, Incremental Search for your Second Brain/ /Natural, Incremental Search for your Second Brain/
** Table of Contents ** Table of Contents

View file

@ -1,2 +1,2 @@
npm node_modules npm node_modules
build build

View file

@ -9,7 +9,7 @@
"eslint:recommended", "eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended", "plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended" "plugin:@typescript-eslint/recommended"
], ],
"parserOptions": { "parserOptions": {
"sourceType": "module" "sourceType": "module"
}, },
@ -19,5 +19,5 @@
"@typescript-eslint/ban-ts-comment": "off", "@typescript-eslint/ban-ts-comment": "off",
"no-prototype-builtins": "off", "no-prototype-builtins": "off",
"@typescript-eslint/no-empty-function": "off" "@typescript-eslint/no-empty-function": "off"
} }
} }

View file

@ -1 +1 @@
tag-version-prefix="" tag-version-prefix=""

View file

@ -619,4 +619,3 @@ Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee. copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS END OF TERMS AND CONDITIONS

View file

@ -7,4 +7,4 @@
"author": "Debanjum Singh Solanky", "author": "Debanjum Singh Solanky",
"authorUrl": "https://github.com/debanjum", "authorUrl": "https://github.com/debanjum",
"isDesktopOnly": false "isDesktopOnly": false
} }

View file

@ -113,4 +113,4 @@ export async function updateKhojBackend(khojUrl: string, khojConfig: Object) {
function getIndexDirectoryFromBackendConfig(khojConfig: any) { function getIndexDirectoryFromBackendConfig(khojConfig: any) {
return khojConfig["content-type"]["markdown"]["embeddings-file"].split("/").slice(0, -1).join("/"); return khojConfig["content-type"]["markdown"]["embeddings-file"].split("/").slice(0, -1).join("/");
} }

View file

@ -3,4 +3,4 @@
"0.2.5": "0.15.0", "0.2.5": "0.15.0",
"0.2.6": "0.15.0", "0.2.6": "0.15.0",
"0.3.0": "0.15.0" "0.3.0": "0.15.0"
} }

View file

@ -26,4 +26,4 @@ span.config-element-value {
button { button {
cursor: pointer; cursor: pointer;
} }

View file

@ -56,10 +56,10 @@ regenerateButton.addEventListener("click", (event) => {
}) })
/** /**
* Adds config elements to the DOM representing the sub-components * Adds config elements to the DOM representing the sub-components
* of one of the fields in the raw config file. * of one of the fields in the raw config file.
* @param {the parent element} element * @param {the parent element} element
* @param {the data to be rendered for this element and its children} data * @param {the data to be rendered for this element and its children} data
*/ */
function processChildren(element, data) { function processChildren(element, data) {
for (let key in data) { for (let key in data) {
@ -78,11 +78,11 @@ function processChildren(element, data) {
} }
/** /**
* Takes an element, and replaces it with an editable * Takes an element, and replaces it with an editable
* element with the same data in place. * element with the same data in place.
* @param {the original element to be replaced} original * @param {the original element to be replaced} original
* @param {the source data to be rendered for the new element} data * @param {the source data to be rendered for the new element} data
* @param {the key for this input in the source data} key * @param {the key for this input in the source data} key
*/ */
function makeElementEditable(original, data, key) { function makeElementEditable(original, data, key) {
original.addEventListener("click", () => { original.addEventListener("click", () => {
@ -98,8 +98,8 @@ function makeElementEditable(original, data, key) {
/** /**
* Creates a node corresponding to the value of a config element. * Creates a node corresponding to the value of a config element.
* @param {the source data} data * @param {the source data} data
* @param {the key corresponding to this node's data} key * @param {the key corresponding to this node's data} key
* @returns A new element which corresponds to the value in some field. * @returns A new element which corresponds to the value in some field.
*/ */
function createValueNode(data, key) { function createValueNode(data, key) {
@ -111,11 +111,11 @@ function createValueNode(data, key) {
} }
/** /**
* Replaces an existing input element with an element with the same data, which is not an input. * Replaces an existing input element with an element with the same data, which is not an input.
* If the input data for this element was changed, update the corresponding data in the raw config. * If the input data for this element was changed, update the corresponding data in the raw config.
* @param {the original element to be replaced} original * @param {the original element to be replaced} original
* @param {the source data} data * @param {the source data} data
* @param {the key corresponding to this node's data} key * @param {the key corresponding to this node's data} key
*/ */
function fixInputOnFocusOut(original, data, key) { function fixInputOnFocusOut(original, data, key) {
original.addEventListener("blur", () => { original.addEventListener("blur", () => {

View file

@ -1,6 +1,6 @@
/*! markdown-it 13.0.1 https://github.com/markdown-it/markdown-it @license MIT */ /*! markdown-it 13.0.1 https://github.com/markdown-it/markdown-it @license MIT */
(function(global, factory) { (function(global, factory) {
typeof exports === "object" && typeof module !== "undefined" ? module.exports = factory() : typeof define === "function" && define.amd ? define(factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, typeof exports === "object" && typeof module !== "undefined" ? module.exports = factory() : typeof define === "function" && define.amd ? define(factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self,
global.markdownit = factory()); global.markdownit = factory());
})(this, (function() { })(this, (function() {
"use strict"; "use strict";
@ -2164,7 +2164,7 @@
var encodeCache = {}; var encodeCache = {};
// Create a lookup array where anything but characters in `chars` string // Create a lookup array where anything but characters in `chars` string
// and alphanumeric chars is percent-encoded. // and alphanumeric chars is percent-encoded.
function getEncodeCache(exclude) { function getEncodeCache(exclude) {
var i, ch, cache = encodeCache[exclude]; var i, ch, cache = encodeCache[exclude];
if (cache) { if (cache) {
@ -2187,11 +2187,11 @@
} }
// Encode unsafe characters with percent-encoding, skipping already // Encode unsafe characters with percent-encoding, skipping already
// encoded sequences. // encoded sequences.
// - string - string to encode // - string - string to encode
// - exclude - list of characters to ignore (in addition to a-zA-Z0-9) // - exclude - list of characters to ignore (in addition to a-zA-Z0-9)
// - keepEscaped - don't encode '%' in a correct escape sequence (default: true) // - keepEscaped - don't encode '%' in a correct escape sequence (default: true)
function encode$2(string, exclude, keepEscaped) { function encode$2(string, exclude, keepEscaped) {
var i, l, code, nextCode, cache, result = ""; var i, l, code, nextCode, cache, result = "";
if (typeof exclude !== "string") { if (typeof exclude !== "string") {
@ -2253,7 +2253,7 @@
return cache; return cache;
} }
// Decode percent-encoded string. // Decode percent-encoded string.
function decode$2(string, exclude) { function decode$2(string, exclude) {
var cache; var cache;
if (typeof exclude !== "string") { if (typeof exclude !== "string") {
@ -2340,26 +2340,26 @@
return result; return result;
}; };
// Copyright Joyent, Inc. and other Node contributors. // Copyright Joyent, Inc. and other Node contributors.
// Changes from joyent/node: // Changes from joyent/node:
// 1. No leading slash in paths, // 1. No leading slash in paths,
// e.g. in `url.parse('http://foo?bar')` pathname is ``, not `/` // e.g. in `url.parse('http://foo?bar')` pathname is ``, not `/`
// 2. Backslashes are not replaced with slashes, // 2. Backslashes are not replaced with slashes,
// so `http:\\example.org\` is treated like a relative path // so `http:\\example.org\` is treated like a relative path
// 3. Trailing colon is treated like a part of the path, // 3. Trailing colon is treated like a part of the path,
// i.e. in `http://example.org:foo` pathname is `:foo` // i.e. in `http://example.org:foo` pathname is `:foo`
// 4. Nothing is URL-encoded in the resulting object, // 4. Nothing is URL-encoded in the resulting object,
// (in joyent/node some chars in auth and paths are encoded) // (in joyent/node some chars in auth and paths are encoded)
// 5. `url.parse()` does not have `parseQueryString` argument // 5. `url.parse()` does not have `parseQueryString` argument
// 6. Removed extraneous result properties: `host`, `path`, `query`, etc., // 6. Removed extraneous result properties: `host`, `path`, `query`, etc.,
// which can be constructed using other parts of the url. // which can be constructed using other parts of the url.
function Url() { function Url() {
this.protocol = null; this.protocol = null;
this.slashes = null; this.slashes = null;
@ -2373,28 +2373,28 @@
// Reference: RFC 3986, RFC 1808, RFC 2396 // Reference: RFC 3986, RFC 1808, RFC 2396
// define these here so at least they only have to be // define these here so at least they only have to be
// compiled once on the first module load. // compiled once on the first module load.
var protocolPattern = /^([a-z0-9.+-]+:)/i, portPattern = /:[0-9]*$/, var protocolPattern = /^([a-z0-9.+-]+:)/i, portPattern = /:[0-9]*$/,
// Special case for a simple path URL // Special case for a simple path URL
simplePathPattern = /^(\/\/?(?!\/)[^\?\s]*)(\?[^\s]*)?$/, simplePathPattern = /^(\/\/?(?!\/)[^\?\s]*)(\?[^\s]*)?$/,
// RFC 2396: characters reserved for delimiting URLs. // RFC 2396: characters reserved for delimiting URLs.
// We actually just auto-escape these. // We actually just auto-escape these.
delims = [ "<", ">", '"', "`", " ", "\r", "\n", "\t" ], delims = [ "<", ">", '"', "`", " ", "\r", "\n", "\t" ],
// RFC 2396: characters not allowed for various reasons. // RFC 2396: characters not allowed for various reasons.
unwise = [ "{", "}", "|", "\\", "^", "`" ].concat(delims), unwise = [ "{", "}", "|", "\\", "^", "`" ].concat(delims),
// Allowed by RFCs, but cause of XSS attacks. Always escape these. // Allowed by RFCs, but cause of XSS attacks. Always escape these.
autoEscape = [ "'" ].concat(unwise), autoEscape = [ "'" ].concat(unwise),
// Characters that are never ever allowed in a hostname. // Characters that are never ever allowed in a hostname.
// Note that any invalid chars are also handled, but these // Note that any invalid chars are also handled, but these
// are the ones that are *expected* to be seen, so we fast-path // are the ones that are *expected* to be seen, so we fast-path
// them. // them.
nonHostChars = [ "%", "/", "?", ";", "#" ].concat(autoEscape), hostEndingChars = [ "/", "?", "#" ], hostnameMaxLen = 255, hostnamePartPattern = /^[+a-z0-9A-Z_-]{0,63}$/, hostnamePartStart = /^([+a-z0-9A-Z_-]{0,63})(.*)$/, nonHostChars = [ "%", "/", "?", ";", "#" ].concat(autoEscape), hostEndingChars = [ "/", "?", "#" ], hostnameMaxLen = 255, hostnamePartPattern = /^[+a-z0-9A-Z_-]{0,63}$/, hostnamePartStart = /^([+a-z0-9A-Z_-]{0,63})(.*)$/,
// protocols that can allow "unsafe" and "unwise" chars. // protocols that can allow "unsafe" and "unwise" chars.
/* eslint-disable no-script-url */ /* eslint-disable no-script-url */
// protocols that never have a hostname. // protocols that never have a hostname.
hostlessProtocol = { hostlessProtocol = {
javascript: true, javascript: true,
"javascript:": true "javascript:": true
}, },
// protocols that always contain a // bit. // protocols that always contain a // bit.
slashedProtocol = { slashedProtocol = {
http: true, http: true,
@ -2632,7 +2632,7 @@
return _hasOwnProperty.call(object, key); return _hasOwnProperty.call(object, key);
} }
// Merge objects // Merge objects
function assign(obj /*from1, from2, from3, ...*/) { function assign(obj /*from1, from2, from3, ...*/) {
var sources = Array.prototype.slice.call(arguments, 1); var sources = Array.prototype.slice.call(arguments, 1);
sources.forEach((function(source) { sources.forEach((function(source) {
@ -2798,12 +2798,12 @@
return regex$4.test(ch); return regex$4.test(ch);
} }
// Markdown ASCII punctuation characters. // Markdown ASCII punctuation characters.
// !, ", #, $, %, &, ', (, ), *, +, ,, -, ., /, :, ;, <, =, >, ?, @, [, \, ], ^, _, `, {, |, }, or ~ // !, ", #, $, %, &, ', (, ), *, +, ,, -, ., /, :, ;, <, =, >, ?, @, [, \, ], ^, _, `, {, |, }, or ~
// http://spec.commonmark.org/0.15/#ascii-punctuation-character // http://spec.commonmark.org/0.15/#ascii-punctuation-character
// Don't confuse with unicode punctuation !!! It lacks some chars in ascii range. // Don't confuse with unicode punctuation !!! It lacks some chars in ascii range.
function isMdAsciiPunct(ch) { function isMdAsciiPunct(ch) {
switch (ch) { switch (ch) {
case 33 /* ! */ : case 33 /* ! */ :
@ -2845,58 +2845,58 @@
} }
} }
// Hepler to unify [reference labels]. // Hepler to unify [reference labels].
function normalizeReference(str) { function normalizeReference(str) {
// Trim and collapse whitespace // Trim and collapse whitespace
str = str.trim().replace(/\s+/g, " "); str = str.trim().replace(/\s+/g, " ");
// In node v10 'ẞ'.toLowerCase() === 'Ṿ', which is presumed to be a bug // In node v10 'ẞ'.toLowerCase() === 'Ṿ', which is presumed to be a bug
// fixed in v12 (couldn't find any details). // fixed in v12 (couldn't find any details).
// So treat this one as a special case // So treat this one as a special case
// (remove this when node v10 is no longer supported). // (remove this when node v10 is no longer supported).
if ("\u1e9e".toLowerCase() === "\u1e7e") { if ("\u1e9e".toLowerCase() === "\u1e7e") {
str = str.replace(/\u1e9e/g, "\xdf"); str = str.replace(/\u1e9e/g, "\xdf");
} }
// .toLowerCase().toUpperCase() should get rid of all differences // .toLowerCase().toUpperCase() should get rid of all differences
// between letter variants. // between letter variants.
// Simple .toLowerCase() doesn't normalize 125 code points correctly, // Simple .toLowerCase() doesn't normalize 125 code points correctly,
// and .toUpperCase doesn't normalize 6 of them (list of exceptions: // and .toUpperCase doesn't normalize 6 of them (list of exceptions:
// İ, ϴ, ẞ, Ω, , Å - those are already uppercased, but have differently // İ, ϴ, ẞ, Ω, , Å - those are already uppercased, but have differently
// uppercased versions). // uppercased versions).
// Here's an example showing how it happens. Lets take greek letter omega: // Here's an example showing how it happens. Lets take greek letter omega:
// uppercase U+0398 (Θ), U+03f4 (ϴ) and lowercase U+03b8 (θ), U+03d1 (ϑ) // uppercase U+0398 (Θ), U+03f4 (ϴ) and lowercase U+03b8 (θ), U+03d1 (ϑ)
// Unicode entries: // Unicode entries:
// 0398;GREEK CAPITAL LETTER THETA;Lu;0;L;;;;;N;;;;03B8; // 0398;GREEK CAPITAL LETTER THETA;Lu;0;L;;;;;N;;;;03B8;
// 03B8;GREEK SMALL LETTER THETA;Ll;0;L;;;;;N;;;0398;;0398 // 03B8;GREEK SMALL LETTER THETA;Ll;0;L;;;;;N;;;0398;;0398
// 03D1;GREEK THETA SYMBOL;Ll;0;L;<compat> 03B8;;;;N;GREEK SMALL LETTER SCRIPT THETA;;0398;;0398 // 03D1;GREEK THETA SYMBOL;Ll;0;L;<compat> 03B8;;;;N;GREEK SMALL LETTER SCRIPT THETA;;0398;;0398
// 03F4;GREEK CAPITAL THETA SYMBOL;Lu;0;L;<compat> 0398;;;;N;;;;03B8; // 03F4;GREEK CAPITAL THETA SYMBOL;Lu;0;L;<compat> 0398;;;;N;;;;03B8;
// Case-insensitive comparison should treat all of them as equivalent. // Case-insensitive comparison should treat all of them as equivalent.
// But .toLowerCase() doesn't change ϑ (it's already lowercase), // But .toLowerCase() doesn't change ϑ (it's already lowercase),
// and .toUpperCase() doesn't change ϴ (already uppercase). // and .toUpperCase() doesn't change ϴ (already uppercase).
// Applying first lower then upper case normalizes any character: // Applying first lower then upper case normalizes any character:
// '\u0398\u03f4\u03b8\u03d1'.toLowerCase().toUpperCase() === '\u0398\u0398\u0398\u0398' // '\u0398\u03f4\u03b8\u03d1'.toLowerCase().toUpperCase() === '\u0398\u0398\u0398\u0398'
// Note: this is equivalent to unicode case folding; unicode normalization // Note: this is equivalent to unicode case folding; unicode normalization
// is a different step that is not required here. // is a different step that is not required here.
// Final result should be uppercased, because it's later stored in an object // Final result should be uppercased, because it's later stored in an object
// (this avoid a conflict with Object.prototype members, // (this avoid a conflict with Object.prototype members,
// most notably, `__proto__`) // most notably, `__proto__`)
return str.toLowerCase().toUpperCase(); return str.toLowerCase().toUpperCase();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Re-export libraries commonly used in both markdown-it and its plugins, // Re-export libraries commonly used in both markdown-it and its plugins,
// so plugins won't have to depend on them explicitly, which reduces their // so plugins won't have to depend on them explicitly, which reduces their
// bundled size (e.g. a browser build). // bundled size (e.g. a browser build).
exports.lib = {}; exports.lib = {};
exports.lib.mdurl = mdurl; exports.lib.mdurl = mdurl;
exports.lib.ucmicro = uc_micro; exports.lib.ucmicro = uc_micro;
@ -3129,7 +3129,7 @@
var token = tokens[idx]; var token = tokens[idx];
// "alt" attr MUST be set, even if empty. Because it's mandatory and // "alt" attr MUST be set, even if empty. Because it's mandatory and
// should be placed on proper position for tests. // should be placed on proper position for tests.
// Replace content with actual value // Replace content with actual value
token.attrs[token.attrIndex("alt")][1] = slf.renderInlineAsText(token.children, options, env); token.attrs[token.attrIndex("alt")][1] = slf.renderInlineAsText(token.children, options, env);
return slf.renderToken(tokens, idx, options); return slf.renderToken(tokens, idx, options);
@ -3215,11 +3215,11 @@
} }
// Insert a newline between hidden paragraph and subsequent opening // Insert a newline between hidden paragraph and subsequent opening
// block-level tag. // block-level tag.
// For example, here we should insert a newline before blockquote: // For example, here we should insert a newline before blockquote:
// - a // - a
// > // >
if (token.block && token.nesting !== -1 && idx && tokens[idx - 1].hidden) { if (token.block && token.nesting !== -1 && idx && tokens[idx - 1].hidden) {
result += "\n"; result += "\n";
} }
@ -3343,16 +3343,16 @@
// } // }
this.__rules__ = []; this.__rules__ = [];
// Cached rule chains. // Cached rule chains.
// First level - chain name, '' for default. // First level - chain name, '' for default.
// Second level - diginal anchor for fast filtering by charcodes. // Second level - diginal anchor for fast filtering by charcodes.
this.__cache__ = null; this.__cache__ = null;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Helper methods, should not be used directly // Helper methods, should not be used directly
// Find rule index by name // Find rule index by name
Ruler.prototype.__find__ = function(name) { Ruler.prototype.__find__ = function(name) {
for (var i = 0; i < this.__rules__.length; i++) { for (var i = 0; i < this.__rules__.length; i++) {
if (this.__rules__[i].name === name) { if (this.__rules__[i].name === name) {
@ -3362,7 +3362,7 @@
return -1; return -1;
}; };
// Build rules lookup cache // Build rules lookup cache
Ruler.prototype.__compile__ = function() { Ruler.prototype.__compile__ = function() {
var self = this; var self = this;
var chains = [ "" ]; var chains = [ "" ];
@ -3726,7 +3726,7 @@
// Linkifier might send raw hostnames like "example.com", where url // Linkifier might send raw hostnames like "example.com", where url
// starts with domain name. So we prepend http:// in those cases, // starts with domain name. So we prepend http:// in those cases,
// and remove it afterwards. // and remove it afterwards.
if (!links[ln].schema) { if (!links[ln].schema) {
urlText = state.md.normalizeLinkText("http://" + urlText).replace(/^http:\/\//, ""); urlText = state.md.normalizeLinkText("http://" + urlText).replace(/^http:\/\//, "");
} else if (links[ln].schema === "mailto:" && !/^mailto:/i.test(urlText)) { } else if (links[ln].schema === "mailto:" && !/^mailto:/i.test(urlText)) {
@ -3874,7 +3874,7 @@
isSingle = t[0] === "'"; isSingle = t[0] === "'";
// Find previous character, // Find previous character,
// default to space if it's the beginning of the line // default to space if it's the beginning of the line
lastChar = 32; lastChar = 32;
if (t.index - 1 >= 0) { if (t.index - 1 >= 0) {
lastChar = text.charCodeAt(t.index - 1); lastChar = text.charCodeAt(t.index - 1);
@ -3890,7 +3890,7 @@
} }
// Find next character, // Find next character,
// default to space if it's the end of the line // default to space if it's the end of the line
nextChar = 32; nextChar = 32;
if (pos < max) { if (pos < max) {
nextChar = text.charCodeAt(pos); nextChar = text.charCodeAt(pos);
@ -4193,7 +4193,7 @@
// re-export Token class to use in core rules // re-export Token class to use in core rules
StateCore.prototype.Token = token; StateCore.prototype.Token = token;
var state_core = StateCore; var state_core = StateCore;
var _rules$2 = [ [ "normalize", normalize ], [ "block", block ], [ "inline", inline ], [ "linkify", linkify$1 ], [ "replacements", replacements ], [ "smartquotes", smartquotes ], var _rules$2 = [ [ "normalize", normalize ], [ "block", block ], [ "inline", inline ], [ "linkify", linkify$1 ], [ "replacements", replacements ], [ "smartquotes", smartquotes ],
// `text_join` finds `text_special` tokens (for escape sequences) // `text_join` finds `text_special` tokens (for escape sequences)
// and joins them with the rest of the text // and joins them with the rest of the text
[ "text_join", text_join ] ]; [ "text_join", text_join ] ];
@ -4590,12 +4590,12 @@
oldParentType = state.parentType; oldParentType = state.parentType;
state.parentType = "blockquote"; state.parentType = "blockquote";
// Search the end of the block // Search the end of the block
// Block ends with either: // Block ends with either:
// 1. an empty line outside: // 1. an empty line outside:
// ``` // ```
// > test // > test
// ``` // ```
// 2. an empty line inside: // 2. an empty line inside:
// ``` // ```
@ -4712,7 +4712,7 @@
oldTShift.push(state.tShift[nextLine]); oldTShift.push(state.tShift[nextLine]);
oldSCount.push(state.sCount[nextLine]); oldSCount.push(state.sCount[nextLine]);
// A negative indentation means that this is a paragraph continuation // A negative indentation means that this is a paragraph continuation
state.sCount[nextLine] = -1; state.sCount[nextLine] = -1;
} }
oldIndent = state.blkIndent; oldIndent = state.blkIndent;
@ -4905,9 +4905,9 @@
} }
token.map = listLines = [ startLine, 0 ]; token.map = listLines = [ startLine, 0 ];
token.markup = String.fromCharCode(markerCharCode); token.markup = String.fromCharCode(markerCharCode);
// Iterate list items // Iterate list items
nextLine = startLine; nextLine = startLine;
prevEmptyEnd = false; prevEmptyEnd = false;
terminatorRules = state.md.block.ruler.getRules("list"); terminatorRules = state.md.block.ruler.getRules("list");
@ -4957,7 +4957,7 @@
// - example list // - example list
// ^ listIndent position will be here // ^ listIndent position will be here
// ^ blkIndent position will be here // ^ blkIndent position will be here
oldListIndent = state.listIndent; oldListIndent = state.listIndent;
state.listIndent = state.blkIndent; state.listIndent = state.blkIndent;
state.blkIndent = indent; state.blkIndent = indent;
@ -4995,9 +4995,9 @@
if (nextLine >= endLine) { if (nextLine >= endLine) {
break; break;
} }
// Try to check if list is terminated or continued. // Try to check if list is terminated or continued.
if (state.sCount[nextLine] < state.blkIndent) { if (state.sCount[nextLine] < state.blkIndent) {
break; break;
} }
@ -5245,7 +5245,7 @@
var HTML_OPEN_CLOSE_TAG_RE = html_re.HTML_OPEN_CLOSE_TAG_RE; var HTML_OPEN_CLOSE_TAG_RE = html_re.HTML_OPEN_CLOSE_TAG_RE;
// An array of opening and corresponding closing sequences for html tags, // An array of opening and corresponding closing sequences for html tags,
// last argument defines whether it can terminate a paragraph or not // last argument defines whether it can terminate a paragraph or not
var HTML_SEQUENCES = [ [ /^<(script|pre|style|textarea)(?=(\s|>|$))/i, /<\/(script|pre|style|textarea)>/i, true ], [ /^<!--/, /-->/, true ], [ /^<\?/, /\?>/, true ], [ /^<![A-Z]/, />/, true ], [ /^<!\[CDATA\[/, /\]\]>/, true ], [ new RegExp("^</?(" + html_blocks.join("|") + ")(?=(\\s|/?>|$))", "i"), /^$/, true ], [ new RegExp(HTML_OPEN_CLOSE_TAG_RE.source + "\\s*$"), /^$/, false ] ]; var HTML_SEQUENCES = [ [ /^<(script|pre|style|textarea)(?=(\s|>|$))/i, /<\/(script|pre|style|textarea)>/i, true ], [ /^<!--/, /-->/, true ], [ /^<\?/, /\?>/, true ], [ /^<![A-Z]/, />/, true ], [ /^<!\[CDATA\[/, /\]\]>/, true ], [ new RegExp("^</?(" + html_blocks.join("|") + ")(?=(\\s|/?>|$))", "i"), /^$/, true ], [ new RegExp(HTML_OPEN_CLOSE_TAG_RE.source + "\\s*$"), /^$/, false ] ];
var html_block = function html_block(state, startLine, endLine, silent) { var html_block = function html_block(state, startLine, endLine, silent) {
var i, nextLine, token, lineText, pos = state.bMarks[startLine] + state.tShift[startLine], max = state.eMarks[startLine]; var i, nextLine, token, lineText, pos = state.bMarks[startLine] + state.tShift[startLine], max = state.eMarks[startLine];
@ -5357,9 +5357,9 @@
if (state.sCount[nextLine] - state.blkIndent > 3) { if (state.sCount[nextLine] - state.blkIndent > 3) {
continue; continue;
} }
// Check for underline in setext header // Check for underline in setext header
if (state.sCount[nextLine] >= state.blkIndent) { if (state.sCount[nextLine] >= state.blkIndent) {
pos = state.bMarks[nextLine] + state.tShift[nextLine]; pos = state.bMarks[nextLine] + state.tShift[nextLine];
max = state.eMarks[nextLine]; max = state.eMarks[nextLine];
@ -5456,9 +5456,9 @@
// link to parser instance // link to parser instance
this.md = md; this.md = md;
this.env = env; this.env = env;
// Internal state vartiables // Internal state vartiables
this.tokens = tokens; this.tokens = tokens;
this.bMarks = []; this.bMarks = [];
// line begin offsets for fast jumps // line begin offsets for fast jumps
@ -5470,14 +5470,14 @@
// indents for each line (tabs expanded) // indents for each line (tabs expanded)
// An amount of virtual spaces (tabs expanded) between beginning // An amount of virtual spaces (tabs expanded) between beginning
// of each line (bMarks) and real beginning of that line. // of each line (bMarks) and real beginning of that line.
// It exists only as a hack because blockquotes override bMarks // It exists only as a hack because blockquotes override bMarks
// losing information in the process. // losing information in the process.
// It's used only when expanding tabs, you can think about it as // It's used only when expanding tabs, you can think about it as
// an initial tab length, e.g. bsCount=21 applied to string `\t123` // an initial tab length, e.g. bsCount=21 applied to string `\t123`
// means first tab should be expanded to 4-21%4 === 3 spaces. // means first tab should be expanded to 4-21%4 === 3 spaces.
this.bsCount = []; this.bsCount = [];
// block parser variables // block parser variables
this.blkIndent = 0; this.blkIndent = 0;
@ -5543,7 +5543,7 @@
// don't count last fake line // don't count last fake line
} }
// Push new token to "stream". // Push new token to "stream".
StateBlock.prototype.push = function(type, tag, nesting) { StateBlock.prototype.push = function(type, tag, nesting) {
var token$1 = new token(type, tag, nesting); var token$1 = new token(type, tag, nesting);
token$1.block = true; token$1.block = true;
@ -5655,7 +5655,7 @@
// re-export Token class to use in block rules // re-export Token class to use in block rules
StateBlock.prototype.Token = token; StateBlock.prototype.Token = token;
var state_block = StateBlock; var state_block = StateBlock;
var _rules$1 = [ var _rules$1 = [
// First 2 params - rule name & source. Secondary array - list of rules, // First 2 params - rule name & source. Secondary array - list of rules,
// which can be terminated by this one. // which can be terminated by this one.
[ "table", table, [ "paragraph", "reference" ] ], [ "code", code ], [ "fence", fence, [ "paragraph", "reference", "blockquote", "list" ] ], [ "blockquote", blockquote, [ "paragraph", "reference", "blockquote", "list" ] ], [ "hr", hr, [ "paragraph", "reference", "blockquote", "list" ] ], [ "list", list, [ "paragraph", "reference", "blockquote" ] ], [ "reference", reference ], [ "html_block", html_block, [ "paragraph", "reference", "blockquote" ] ], [ "heading", heading, [ "paragraph", "reference", "blockquote" ] ], [ "lheading", lheading ], [ "paragraph", paragraph ] ]; [ "table", table, [ "paragraph", "reference" ] ], [ "code", code ], [ "fence", fence, [ "paragraph", "reference", "blockquote", "list" ] ], [ "blockquote", blockquote, [ "paragraph", "reference", "blockquote", "list" ] ], [ "hr", hr, [ "paragraph", "reference", "blockquote", "list" ] ], [ "list", list, [ "paragraph", "reference", "blockquote" ] ], [ "reference", reference ], [ "html_block", html_block, [ "paragraph", "reference", "blockquote" ] ], [ "heading", heading, [ "paragraph", "reference", "blockquote" ] ], [ "lheading", lheading ], [ "paragraph", paragraph ] ];
@ -5675,7 +5675,7 @@
} }
} }
// Generate tokens for input range // Generate tokens for input range
ParserBlock.prototype.tokenize = function(state, startLine, endLine) { ParserBlock.prototype.tokenize = function(state, startLine, endLine) {
var ok, i, rules = this.ruler.getRules(""), len = rules.length, line = startLine, hasEmptyLines = false, maxNesting = state.md.options.maxNesting; var ok, i, rules = this.ruler.getRules(""), len = rules.length, line = startLine, hasEmptyLines = false, maxNesting = state.md.options.maxNesting;
while (line < endLine) { while (line < endLine) {
@ -5696,7 +5696,7 @@
} }
// Try all possible rules. // Try all possible rules.
// On success, rule should: // On success, rule should:
// - update `state.line` // - update `state.line`
// - update `state.tokens` // - update `state.tokens`
// - return true // - return true
@ -5961,7 +5961,7 @@
}; };
// ~~strike through~~ // ~~strike through~~
// Insert each marker as a separate text token, and add it to delimiter list // Insert each marker as a separate text token, and add it to delimiter list
var tokenize$1 = function strikethrough(state, silent) { var tokenize$1 = function strikethrough(state, silent) {
var i, scanned, token, len, ch, start = state.pos, marker = state.src.charCodeAt(start); var i, scanned, token, len, ch, start = state.pos, marker = state.src.charCodeAt(start);
if (silent) { if (silent) {
@ -6027,9 +6027,9 @@
// If a marker sequence has an odd number of characters, it's splitted // If a marker sequence has an odd number of characters, it's splitted
// like this: `~~~~~` -> `~` + `~~` + `~~`, leaving one marker at the // like this: `~~~~~` -> `~` + `~~` + `~~`, leaving one marker at the
// start of the sequence. // start of the sequence.
// So, we have to move all those markers after subsequent s_close tags. // So, we have to move all those markers after subsequent s_close tags.
while (loneMarkers.length) { while (loneMarkers.length) {
i = loneMarkers.pop(); i = loneMarkers.pop();
j = i + 1; j = i + 1;
@ -6045,7 +6045,7 @@
} }
} }
// Walk through delimiter list and replace text tokens with tags // Walk through delimiter list and replace text tokens with tags
var postProcess_1$1 = function strikethrough(state) { var postProcess_1$1 = function strikethrough(state) {
var curr, tokens_meta = state.tokens_meta, max = state.tokens_meta.length; var curr, tokens_meta = state.tokens_meta, max = state.tokens_meta.length;
postProcess$1(state, state.delimiters); postProcess$1(state, state.delimiters);
@ -6061,7 +6061,7 @@
}; };
// Process *this* and _that_ // Process *this* and _that_
// Insert each marker as a separate text token, and add it to delimiter list // Insert each marker as a separate text token, and add it to delimiter list
var tokenize = function emphasis(state, silent) { var tokenize = function emphasis(state, silent) {
var i, scanned, token, start = state.pos, marker = state.src.charCodeAt(start); var i, scanned, token, start = state.pos, marker = state.src.charCodeAt(start);
if (silent) { if (silent) {
@ -6107,12 +6107,12 @@
endDelim = delimiters[startDelim.end]; endDelim = delimiters[startDelim.end];
// If the previous delimiter has the same marker and is adjacent to this one, // If the previous delimiter has the same marker and is adjacent to this one,
// merge those into one strong delimiter. // merge those into one strong delimiter.
// `<em><em>whatever</em></em>` -> `<strong>whatever</strong>` // `<em><em>whatever</em></em>` -> `<strong>whatever</strong>`
isStrong = i > 0 && delimiters[i - 1].end === startDelim.end + 1 && isStrong = i > 0 && delimiters[i - 1].end === startDelim.end + 1 &&
// check that first two markers match and adjacent // check that first two markers match and adjacent
delimiters[i - 1].marker === startDelim.marker && delimiters[i - 1].token === startDelim.token - 1 && delimiters[i - 1].marker === startDelim.marker && delimiters[i - 1].token === startDelim.token - 1 &&
// check that last two markers are adjacent (we can safely assume they match) // check that last two markers are adjacent (we can safely assume they match)
delimiters[startDelim.end + 1].token === endDelim.token + 1; delimiters[startDelim.end + 1].token === endDelim.token + 1;
ch = String.fromCharCode(startDelim.marker); ch = String.fromCharCode(startDelim.marker);
@ -6136,7 +6136,7 @@
} }
} }
// Walk through delimiter list and replace text tokens with tags // Walk through delimiter list and replace text tokens with tags
var postProcess_1 = function emphasis(state) { var postProcess_1 = function emphasis(state) {
var curr, tokens_meta = state.tokens_meta, max = state.tokens_meta.length; var curr, tokens_meta = state.tokens_meta, max = state.tokens_meta.length;
postProcess(state, state.delimiters); postProcess(state, state.delimiters);
@ -6251,10 +6251,10 @@
href = ref.href; href = ref.href;
title = ref.title; title = ref.title;
} }
// We found the end of the link, and know for a fact it's a valid link; // We found the end of the link, and know for a fact it's a valid link;
// so all that's left to do is to call tokenizer. // so all that's left to do is to call tokenizer.
if (!silent) { if (!silent) {
state.pos = labelStart; state.pos = labelStart;
state.posMax = labelEnd; state.posMax = labelEnd;
@ -6375,10 +6375,10 @@
href = ref.href; href = ref.href;
title = ref.title; title = ref.title;
} }
// We found the end of the link, and know for a fact it's a valid link; // We found the end of the link, and know for a fact it's a valid link;
// so all that's left to do is to call tokenizer. // so all that's left to do is to call tokenizer.
if (!silent) { if (!silent) {
content = state.src.slice(labelStart, labelEnd); content = state.src.slice(labelStart, labelEnd);
state.md.inline.parse(content, state.md, state.env, tokens = []); state.md.inline.parse(content, state.md, state.env, tokens = []);
@ -6547,7 +6547,7 @@
// markers belong to same delimiter run if: // markers belong to same delimiter run if:
// - they have adjacent tokens // - they have adjacent tokens
// - AND markers are the same // - AND markers are the same
if (delimiters[headerIdx].marker !== closer.marker || lastTokenIdx !== closer.token - 1) { if (delimiters[headerIdx].marker !== closer.marker || lastTokenIdx !== closer.token - 1) {
headerIdx = closerIdx; headerIdx = closerIdx;
} }
@ -6555,7 +6555,7 @@
// Length is only used for emphasis-specific "rule of 3", // Length is only used for emphasis-specific "rule of 3",
// if it's not defined (in strikethrough or 3rd party plugins), // if it's not defined (in strikethrough or 3rd party plugins),
// we can default it to 0 to disable those checks. // we can default it to 0 to disable those checks.
closer.length = closer.length || 0; closer.length = closer.length || 0;
if (!closer.close) continue; if (!closer.close) continue;
// Previously calculated lower bounds (previous fails) // Previously calculated lower bounds (previous fails)
@ -6574,12 +6574,12 @@
if (opener.open && opener.end < 0) { if (opener.open && opener.end < 0) {
isOddMatch = false; isOddMatch = false;
// from spec: // from spec:
// If one of the delimiters can both open and close emphasis, then the // If one of the delimiters can both open and close emphasis, then the
// sum of the lengths of the delimiter runs containing the opening and // sum of the lengths of the delimiter runs containing the opening and
// closing delimiters must not be a multiple of 3 unless both lengths // closing delimiters must not be a multiple of 3 unless both lengths
// are multiples of 3. // are multiples of 3.
if (opener.close || closer.open) { if (opener.close || closer.open) {
if ((opener.length + closer.length) % 3 === 0) { if ((opener.length + closer.length) % 3 === 0) {
if (opener.length % 3 !== 0 || closer.length % 3 !== 0) { if (opener.length % 3 !== 0 || closer.length % 3 !== 0) {
@ -6678,7 +6678,7 @@
this.linkLevel = 0; this.linkLevel = 0;
} }
// Flush pending text // Flush pending text
StateInline.prototype.pushPending = function() { StateInline.prototype.pushPending = function() {
var token$1 = new token("text", "", 0); var token$1 = new token("text", "", 0);
token$1.content = this.pending; token$1.content = this.pending;
@ -6689,7 +6689,7 @@
}; };
// Push new token to "stream". // Push new token to "stream".
// If pending text exists - flush it as text token // If pending text exists - flush it as text token
StateInline.prototype.push = function(type, tag, nesting) { StateInline.prototype.push = function(type, tag, nesting) {
if (this.pending) { if (this.pending) {
this.pushPending(); this.pushPending();
@ -6718,10 +6718,10 @@
}; };
// Scan a sequence of emphasis-like markers, and determine whether // Scan a sequence of emphasis-like markers, and determine whether
// it can start an emphasis sequence or end an emphasis sequence. // it can start an emphasis sequence or end an emphasis sequence.
// - start - position to scan from (it should point at a valid marker); // - start - position to scan from (it should point at a valid marker);
// - canSplitWord - determine if these markers can be found inside a word // - canSplitWord - determine if these markers can be found inside a word
StateInline.prototype.scanDelims = function(start, canSplitWord) { StateInline.prototype.scanDelims = function(start, canSplitWord) {
var pos = start, lastChar, nextChar, count, can_open, can_close, isLastWhiteSpace, isLastPunctChar, isNextWhiteSpace, isNextPunctChar, left_flanking = true, right_flanking = true, max = this.posMax, marker = this.src.charCodeAt(start); var pos = start, lastChar, nextChar, count, can_open, can_close, isLastWhiteSpace, isLastPunctChar, isNextWhiteSpace, isNextPunctChar, left_flanking = true, right_flanking = true, max = this.posMax, marker = this.src.charCodeAt(start);
// treat beginning of the line as a whitespace // treat beginning of the line as a whitespace
@ -6771,10 +6771,10 @@
var _rules = [ [ "text", text ], [ "linkify", linkify ], [ "newline", newline ], [ "escape", _escape ], [ "backticks", backticks ], [ "strikethrough", strikethrough.tokenize ], [ "emphasis", emphasis.tokenize ], [ "link", link ], [ "image", image ], [ "autolink", autolink ], [ "html_inline", html_inline ], [ "entity", entity ] ]; var _rules = [ [ "text", text ], [ "linkify", linkify ], [ "newline", newline ], [ "escape", _escape ], [ "backticks", backticks ], [ "strikethrough", strikethrough.tokenize ], [ "emphasis", emphasis.tokenize ], [ "link", link ], [ "image", image ], [ "autolink", autolink ], [ "html_inline", html_inline ], [ "entity", entity ] ];
// `rule2` ruleset was created specifically for emphasis/strikethrough // `rule2` ruleset was created specifically for emphasis/strikethrough
// post-processing and may be changed in the future. // post-processing and may be changed in the future.
// Don't use this for anything except pairs (plugins working with `balance_pairs`). // Don't use this for anything except pairs (plugins working with `balance_pairs`).
var _rules2 = [ [ "balance_pairs", balance_pairs ], [ "strikethrough", strikethrough.postProcess ], [ "emphasis", emphasis.postProcess ], var _rules2 = [ [ "balance_pairs", balance_pairs ], [ "strikethrough", strikethrough.postProcess ], [ "emphasis", emphasis.postProcess ],
// rules for pairs separate '**' into its own text tokens, which may be left unused, // rules for pairs separate '**' into its own text tokens, which may be left unused,
// rule below merges unused segments back with the rest of the text // rule below merges unused segments back with the rest of the text
[ "fragments_join", fragments_join ] ]; [ "fragments_join", fragments_join ] ];
@ -6802,7 +6802,7 @@
} }
// Skip single token by running all rules in validation mode; // Skip single token by running all rules in validation mode;
// returns `true` if any rule reported success // returns `true` if any rule reported success
ParserInline.prototype.skipToken = function(state) { ParserInline.prototype.skipToken = function(state) {
var ok, i, pos = state.pos, rules = this.ruler.getRules(""), len = rules.length, maxNesting = state.md.options.maxNesting, cache = state.cache; var ok, i, pos = state.pos, rules = this.ruler.getRules(""), len = rules.length, maxNesting = state.md.options.maxNesting, cache = state.cache;
if (typeof cache[pos] !== "undefined") { if (typeof cache[pos] !== "undefined") {
@ -6837,7 +6837,7 @@
cache[pos] = state.pos; cache[pos] = state.pos;
}; };
// Generate tokens for input range // Generate tokens for input range
ParserInline.prototype.tokenize = function(state) { ParserInline.prototype.tokenize = function(state) {
var ok, i, rules = this.ruler.getRules(""), len = rules.length, end = state.posMax, maxNesting = state.md.options.maxNesting; var ok, i, rules = this.ruler.getRules(""), len = rules.length, end = state.posMax, maxNesting = state.md.options.maxNesting;
while (state.pos < end) { while (state.pos < end) {
@ -6928,11 +6928,11 @@
re.src_xn = "xn--[a-z0-9\\-]{1,59}"; re.src_xn = "xn--[a-z0-9\\-]{1,59}";
// More to read about domain names // More to read about domain names
// http://serverfault.com/questions/638260/ // http://serverfault.com/questions/638260/
re.src_domain_root = re.src_domain_root =
// Allow letters & digits (http://test1) // Allow letters & digits (http://test1)
"(?:" + re.src_xn + "|" + re.src_pseudo_letter + "{1,63}" + ")"; "(?:" + re.src_xn + "|" + re.src_pseudo_letter + "{1,63}" + ")";
re.src_domain = "(?:" + re.src_xn + "|" + "(?:" + re.src_pseudo_letter + ")" + "|" + "(?:" + re.src_pseudo_letter + "(?:-|" + re.src_pseudo_letter + "){0,61}" + re.src_pseudo_letter + ")" + ")"; re.src_domain = "(?:" + re.src_xn + "|" + "(?:" + re.src_pseudo_letter + ")" + "|" + "(?:" + re.src_pseudo_letter + "(?:-|" + re.src_pseudo_letter + "){0,61}" + re.src_pseudo_letter + ")" + ")";
re.src_host = "(?:" + re.src_host = "(?:" +
// Don't need IP check, because digits are already allowed in normal domain names // Don't need IP check, because digits are already allowed in normal domain names
// src_ip4 + // src_ip4 +
// '|' + // '|' +
@ -6949,11 +6949,11 @@
// Rude test fuzzy links by host, for quick deny // Rude test fuzzy links by host, for quick deny
re.tpl_host_fuzzy_test = "localhost|www\\.|\\.\\d{1,3}\\.|(?:\\.(?:%TLDS%)(?:" + re.src_ZPCc + "|>|$))"; re.tpl_host_fuzzy_test = "localhost|www\\.|\\.\\d{1,3}\\.|(?:\\.(?:%TLDS%)(?:" + re.src_ZPCc + "|>|$))";
re.tpl_email_fuzzy = "(^|" + text_separators + '|"|\\(|' + re.src_ZCc + ")" + "(" + re.src_email_name + "@" + re.tpl_host_fuzzy_strict + ")"; re.tpl_email_fuzzy = "(^|" + text_separators + '|"|\\(|' + re.src_ZCc + ")" + "(" + re.src_email_name + "@" + re.tpl_host_fuzzy_strict + ")";
re.tpl_link_fuzzy = re.tpl_link_fuzzy =
// Fuzzy link can't be prepended with .:/\- and non punctuation. // Fuzzy link can't be prepended with .:/\- and non punctuation.
// but can start with > (markdown blockquote) // but can start with > (markdown blockquote)
"(^|(?![.:/\\-_@])(?:[$+<=>^`|\uff5c]|" + re.src_ZPCc + "))" + "((?![$+<=>^`|\uff5c])" + re.tpl_host_port_fuzzy_strict + re.src_path + ")"; "(^|(?![.:/\\-_@])(?:[$+<=>^`|\uff5c]|" + re.src_ZPCc + "))" + "((?![$+<=>^`|\uff5c])" + re.tpl_host_port_fuzzy_strict + re.src_path + ")";
re.tpl_link_no_ip_fuzzy = re.tpl_link_no_ip_fuzzy =
// Fuzzy link can't be prepended with .:/\- and non punctuation. // Fuzzy link can't be prepended with .:/\- and non punctuation.
// but can start with > (markdown blockquote) // but can start with > (markdown blockquote)
"(^|(?![.:/\\-_@])(?:[$+<=>^`|\uff5c]|" + re.src_ZPCc + "))" + "((?![$+<=>^`|\uff5c])" + re.tpl_host_port_no_ip_fuzzy_strict + re.src_path + ")"; "(^|(?![.:/\\-_@])(?:[$+<=>^`|\uff5c]|" + re.src_ZPCc + "))" + "((?![$+<=>^`|\uff5c])" + re.tpl_host_port_no_ip_fuzzy_strict + re.src_path + ")";
@ -6962,7 +6962,7 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Helpers // Helpers
// Merge objects // Merge objects
function assign(obj /*from1, from2, from3, ...*/) { function assign(obj /*from1, from2, from3, ...*/) {
var sources = Array.prototype.slice.call(arguments, 1); var sources = Array.prototype.slice.call(arguments, 1);
sources.forEach((function(source) { sources.forEach((function(source) {
@ -7025,7 +7025,7 @@
var tail = text.slice(pos); var tail = text.slice(pos);
if (!self.re.no_http) { if (!self.re.no_http) {
// compile lazily, because "host"-containing variables can change on tlds update. // compile lazily, because "host"-containing variables can change on tlds update.
self.re.no_http = new RegExp("^" + self.re.src_auth + self.re.no_http = new RegExp("^" + self.re.src_auth +
// Don't allow single-level domains, because of false positives like '//test' // Don't allow single-level domains, because of false positives like '//test'
// with code comments // with code comments
"(?:localhost|(?:(?:" + self.re.src_domain + ")\\.)+" + self.re.src_domain_root + ")" + self.re.src_port + self.re.src_host_terminator + self.re.src_path, "i"); "(?:localhost|(?:(?:" + self.re.src_domain + ")\\.)+" + self.re.src_domain_root + ")" + self.re.src_port + self.re.src_host_terminator + self.re.src_path, "i");
@ -7082,7 +7082,7 @@
}; };
} }
// Schemas compiler. Build regexps. // Schemas compiler. Build regexps.
function compile(self) { function compile(self) {
// Load & clone RE patterns. // Load & clone RE patterns.
var re$1 = self.re = re(self.__opts__); var re$1 = self.re = re(self.__opts__);
@ -7101,9 +7101,9 @@
re$1.link_fuzzy = RegExp(untpl(re$1.tpl_link_fuzzy), "i"); re$1.link_fuzzy = RegExp(untpl(re$1.tpl_link_fuzzy), "i");
re$1.link_no_ip_fuzzy = RegExp(untpl(re$1.tpl_link_no_ip_fuzzy), "i"); re$1.link_no_ip_fuzzy = RegExp(untpl(re$1.tpl_link_no_ip_fuzzy), "i");
re$1.host_fuzzy_test = RegExp(untpl(re$1.tpl_host_fuzzy_test), "i"); re$1.host_fuzzy_test = RegExp(untpl(re$1.tpl_host_fuzzy_test), "i");
// Compile each schema // Compile each schema
var aliases = []; var aliases = [];
self.__compiled__ = {}; self.__compiled__ = {};
// Reset compiled data // Reset compiled data
@ -7144,9 +7144,9 @@
} }
schemaError(name, val); schemaError(name, val);
})); }));
// Compile postponed aliases // Compile postponed aliases
aliases.forEach((function(alias) { aliases.forEach((function(alias) {
if (!self.__compiled__[self.__schemas__[alias]]) { if (!self.__compiled__[self.__schemas__[alias]]) {
// Silently fail on missed schemas to avoid errons on disable. // Silently fail on missed schemas to avoid errons on disable.
@ -7156,16 +7156,16 @@
self.__compiled__[alias].validate = self.__compiled__[self.__schemas__[alias]].validate; self.__compiled__[alias].validate = self.__compiled__[self.__schemas__[alias]].validate;
self.__compiled__[alias].normalize = self.__compiled__[self.__schemas__[alias]].normalize; self.__compiled__[alias].normalize = self.__compiled__[self.__schemas__[alias]].normalize;
})); }));
// Fake record for guessed links // Fake record for guessed links
self.__compiled__[""] = { self.__compiled__[""] = {
validate: null, validate: null,
normalize: createNormalizer() normalize: createNormalizer()
}; };
// Build schema condition // Build schema condition
var slist = Object.keys(self.__compiled__).filter((function(name) { var slist = Object.keys(self.__compiled__).filter((function(name) {
// Filter disabled & fake schemas // Filter disabled & fake schemas
return name.length > 0 && self.__compiled__[name]; return name.length > 0 && self.__compiled__[name];
@ -7175,9 +7175,9 @@
self.re.schema_search = RegExp("(^|(?!_)(?:[><\uff5c]|" + re$1.src_ZPCc + "))(" + slist + ")", "ig"); self.re.schema_search = RegExp("(^|(?!_)(?:[><\uff5c]|" + re$1.src_ZPCc + "))(" + slist + ")", "ig");
self.re.schema_at_start = RegExp("^" + self.re.schema_search.source, "i"); self.re.schema_at_start = RegExp("^" + self.re.schema_search.source, "i");
self.re.pretest = RegExp("(" + self.re.schema_test.source + ")|(" + self.re.host_fuzzy_test.source + ")|@", "i"); self.re.pretest = RegExp("(" + self.re.schema_test.source + ")|(" + self.re.host_fuzzy_test.source + ")|@", "i");
// Cleanup // Cleanup
resetScanCache(self); resetScanCache(self);
} }
/** /**
@ -7673,7 +7673,7 @@
* @returns {String} The resulting string of Unicode symbols. * @returns {String} The resulting string of Unicode symbols.
*/ function decode(input) { */ function decode(input) {
// Don't use UCS-2 // Don't use UCS-2
var output = [], inputLength = input.length, out, i = 0, n = initialN, bias = initialBias, basic, j, index, oldi, w, k, digit, t, var output = [], inputLength = input.length, out, i = 0, n = initialN, bias = initialBias, basic, j, index, oldi, w, k, digit, t,
/** Cached calculation results */ /** Cached calculation results */
baseMinusT; baseMinusT;
// Handle the basic code points: let `basic` be the number of input code // Handle the basic code points: let `basic` be the number of input code
@ -7738,9 +7738,9 @@
* @param {String} input The string of Unicode symbols. * @param {String} input The string of Unicode symbols.
* @returns {String} The resulting Punycode string of ASCII-only symbols. * @returns {String} The resulting Punycode string of ASCII-only symbols.
*/ function encode(input) { */ function encode(input) {
var n, delta, handledCPCount, basicLength, bias, j, m, q, k, t, currentValue, output = [], var n, delta, handledCPCount, basicLength, bias, j, m, q, k, t, currentValue, output = [],
/** `inputLength` will hold the number of code points in `input`. */ /** `inputLength` will hold the number of code points in `input`. */
inputLength, inputLength,
/** Cached calculation results */ /** Cached calculation results */
handledCPCountPlusOne, baseMinusT, qMinusT; handledCPCountPlusOne, baseMinusT, qMinusT;
// Convert the input in UCS-2 to Unicode // Convert the input in UCS-2 to Unicode
@ -7993,13 +7993,13 @@
commonmark: commonmark commonmark: commonmark
}; };
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// This validator can prohibit more than really needed to prevent XSS. It's a // This validator can prohibit more than really needed to prevent XSS. It's a
// tradeoff to keep code simple and to be secure by default. // tradeoff to keep code simple and to be secure by default.
// If you need different setup - override validator method as you wish. Or // If you need different setup - override validator method as you wish. Or
// replace it with dummy function and use external sanitizer. // replace it with dummy function and use external sanitizer.
var BAD_PROTO_RE = /^(vbscript|javascript|file|data):/; var BAD_PROTO_RE = /^(vbscript|javascript|file|data):/;
var GOOD_DATA_RE = /^data:image\/(gif|png|jpeg|webp);/; var GOOD_DATA_RE = /^data:image\/(gif|png|jpeg|webp);/;
function validateLink(url) { function validateLink(url) {

View file

@ -220,7 +220,7 @@ Body 2
def test_parse_entry_with_empty_title(tmp_path): def test_parse_entry_with_empty_title(tmp_path):
"Test parsing of entry with minimal fields" "Test parsing of entry with minimal fields"
# Arrange # Arrange
entry = f"""#+TITLE: entry = f"""#+TITLE:
Body Line 1""" Body Line 1"""
orgfile = create_file(tmp_path, entry) orgfile = create_file(tmp_path, entry)
@ -266,7 +266,7 @@ Body Line 1"""
def test_parse_entry_with_multiple_titles_and_no_headings(tmp_path): def test_parse_entry_with_multiple_titles_and_no_headings(tmp_path):
"Test parsing of entry with minimal fields" "Test parsing of entry with minimal fields"
# Arrange # Arrange
entry = f"""#+TITLE: title1 entry = f"""#+TITLE: title1
Body Line 1 Body Line 1
#+TITLE: title2 """ #+TITLE: title2 """
orgfile = create_file(tmp_path, entry) orgfile = create_file(tmp_path, entry)