mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-17 17:00:15 +01:00
Use react markdown as default, cleanup dependencies
This commit is contained in:
parent
e8e512a451
commit
40e23b013a
18 changed files with 27 additions and 838 deletions
|
|
@ -6,7 +6,6 @@ const customClient = require('./clients/chatgpt-custom');
|
||||||
const titleConvo = require('./titleConvo');
|
const titleConvo = require('./titleConvo');
|
||||||
const getCitations = require('../lib/parse/getCitations');
|
const getCitations = require('../lib/parse/getCitations');
|
||||||
const citeText = require('../lib/parse/citeText');
|
const citeText = require('../lib/parse/citeText');
|
||||||
const detectCode = require('../lib/parse/detectCode');
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
askClient,
|
askClient,
|
||||||
|
|
@ -17,5 +16,4 @@ module.exports = {
|
||||||
titleConvo,
|
titleConvo,
|
||||||
getCitations,
|
getCitations,
|
||||||
citeText,
|
citeText,
|
||||||
detectCode
|
|
||||||
};
|
};
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
const citationRegex = /\[\^\d+?\^]/g;
|
const citationRegex = /\[\^\d+?\^\]/g;
|
||||||
|
|
||||||
const citeText = (res, noLinks = false) => {
|
const citeText = (res, noLinks = false) => {
|
||||||
let result = res.text || res;
|
let result = res.text || res;
|
||||||
|
|
|
||||||
|
|
@ -1,52 +0,0 @@
|
||||||
const { ModelOperations } = require('@vscode/vscode-languagedetection');
|
|
||||||
const languages = require('./languages.js');
|
|
||||||
const codeRegex = /(```[\s\S]*?```)/g;
|
|
||||||
// const languageMatch = /```(\w+)/;
|
|
||||||
const replaceRegex = /```\w+\n/g;
|
|
||||||
|
|
||||||
const detectCode = async (input) => {
|
|
||||||
try {
|
|
||||||
let text = input;
|
|
||||||
if (!text.match(codeRegex)) {
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
|
|
||||||
const langMatches = text.match(replaceRegex);
|
|
||||||
|
|
||||||
if (langMatches?.length > 0) {
|
|
||||||
langMatches.forEach(match => {
|
|
||||||
let lang = match.split('```')[1].trim();
|
|
||||||
|
|
||||||
if (languages.has(lang)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('[detectCode.js] replacing', match, 'with', '```shell');
|
|
||||||
text = text.replace(match, '```shell\n');
|
|
||||||
});
|
|
||||||
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
|
|
||||||
const modelOperations = new ModelOperations();
|
|
||||||
const regexSplit = (await import('./regexSplit.mjs')).default;
|
|
||||||
const parts = regexSplit(text, codeRegex);
|
|
||||||
|
|
||||||
const output = parts.map(async (part) => {
|
|
||||||
if (part.match(codeRegex)) {
|
|
||||||
const code = part.slice(3, -3);
|
|
||||||
let lang = (await modelOperations.runModel(code))[0].languageId;
|
|
||||||
return part.replace(/^```/, `\`\`\`${languages.has(lang) ? lang : 'shell'}`);
|
|
||||||
} else {
|
|
||||||
return part;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return (await Promise.all(output)).join('');
|
|
||||||
} catch (e) {
|
|
||||||
console.log('Error in detectCode function\n', e);
|
|
||||||
return input;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = detectCode;
|
|
||||||
|
|
@ -1,318 +0,0 @@
|
||||||
const languages = new Set([
|
|
||||||
'adoc',
|
|
||||||
'apacheconf',
|
|
||||||
'arm',
|
|
||||||
'as',
|
|
||||||
'asc',
|
|
||||||
'atom',
|
|
||||||
'bat',
|
|
||||||
'bf',
|
|
||||||
'bind',
|
|
||||||
'c++',
|
|
||||||
'capnp',
|
|
||||||
'cc',
|
|
||||||
'clj',
|
|
||||||
'cls',
|
|
||||||
'cmake.in',
|
|
||||||
'cmd',
|
|
||||||
'coffee',
|
|
||||||
'console',
|
|
||||||
'cr',
|
|
||||||
'craftcms',
|
|
||||||
'crm',
|
|
||||||
'cs',
|
|
||||||
'cson',
|
|
||||||
'cts',
|
|
||||||
'cxx',
|
|
||||||
'dfm',
|
|
||||||
'docker',
|
|
||||||
'dst',
|
|
||||||
'erl',
|
|
||||||
'f90',
|
|
||||||
'f95',
|
|
||||||
'fs',
|
|
||||||
'gawk',
|
|
||||||
'gemspec',
|
|
||||||
'gms',
|
|
||||||
'golang',
|
|
||||||
'gololang',
|
|
||||||
'gss',
|
|
||||||
'gyp',
|
|
||||||
'h',
|
|
||||||
'h++',
|
|
||||||
'hbs',
|
|
||||||
'hh',
|
|
||||||
'hpp',
|
|
||||||
'hs',
|
|
||||||
'html',
|
|
||||||
'html.handlebars',
|
|
||||||
'html.hbs',
|
|
||||||
'https',
|
|
||||||
'hx',
|
|
||||||
'hxx',
|
|
||||||
'hylang',
|
|
||||||
'i7',
|
|
||||||
'iced',
|
|
||||||
'ino',
|
|
||||||
'instances',
|
|
||||||
'irb',
|
|
||||||
'jinja',
|
|
||||||
'js',
|
|
||||||
'jsp',
|
|
||||||
'jsx',
|
|
||||||
'julia-repl',
|
|
||||||
'kdb',
|
|
||||||
'kt',
|
|
||||||
'lassoscript',
|
|
||||||
'ls',
|
|
||||||
'ls',
|
|
||||||
'mak',
|
|
||||||
'make',
|
|
||||||
'mawk',
|
|
||||||
'md',
|
|
||||||
'mipsasm',
|
|
||||||
'mk',
|
|
||||||
'mkd',
|
|
||||||
'mkdown',
|
|
||||||
'ml',
|
|
||||||
'ml',
|
|
||||||
'mm',
|
|
||||||
'mma',
|
|
||||||
'moon',
|
|
||||||
'mts',
|
|
||||||
'nawk',
|
|
||||||
'nc',
|
|
||||||
'nginxconf',
|
|
||||||
'nimrod',
|
|
||||||
'objc',
|
|
||||||
'obj-c',
|
|
||||||
'obj-c++',
|
|
||||||
'objective-c++',
|
|
||||||
'osascript',
|
|
||||||
'pas',
|
|
||||||
'pascal',
|
|
||||||
'patch',
|
|
||||||
'pcmk',
|
|
||||||
'pf.conf',
|
|
||||||
'pl',
|
|
||||||
'plist',
|
|
||||||
'pm',
|
|
||||||
'podspec',
|
|
||||||
'postgres',
|
|
||||||
'postgresql',
|
|
||||||
'pp',
|
|
||||||
'ps',
|
|
||||||
'ps1',
|
|
||||||
'py',
|
|
||||||
'pycon',
|
|
||||||
'rb',
|
|
||||||
're',
|
|
||||||
'rs',
|
|
||||||
'rss',
|
|
||||||
'sas',
|
|
||||||
'scad',
|
|
||||||
'sci',
|
|
||||||
'sh',
|
|
||||||
'st',
|
|
||||||
'stanfuncs',
|
|
||||||
'step',
|
|
||||||
'stp',
|
|
||||||
'styl',
|
|
||||||
'svg',
|
|
||||||
'tao',
|
|
||||||
'text',
|
|
||||||
'thor',
|
|
||||||
'tk',
|
|
||||||
'toml',
|
|
||||||
'ts',
|
|
||||||
'tsx',
|
|
||||||
'txt',
|
|
||||||
'v',
|
|
||||||
'vb',
|
|
||||||
'vbs',
|
|
||||||
'wl',
|
|
||||||
'x++',
|
|
||||||
'xhtml',
|
|
||||||
'xjb',
|
|
||||||
'xls',
|
|
||||||
'xlsx',
|
|
||||||
'xpath',
|
|
||||||
'xq',
|
|
||||||
'xsd',
|
|
||||||
'xsl',
|
|
||||||
'yaml',
|
|
||||||
'zep',
|
|
||||||
'zone',
|
|
||||||
'zsh',
|
|
||||||
'1c',
|
|
||||||
'abnf',
|
|
||||||
'accesslog',
|
|
||||||
'actionscript',
|
|
||||||
'ada',
|
|
||||||
'angelscript',
|
|
||||||
'apache',
|
|
||||||
'applescript',
|
|
||||||
'arcade',
|
|
||||||
'arduino',
|
|
||||||
'armasm',
|
|
||||||
'asciidoc',
|
|
||||||
'aspectj',
|
|
||||||
'autohotkey',
|
|
||||||
'autoit',
|
|
||||||
'avrasm',
|
|
||||||
'awk',
|
|
||||||
'axapta',
|
|
||||||
'bash',
|
|
||||||
'basic',
|
|
||||||
'bnf',
|
|
||||||
'brainfuck',
|
|
||||||
'c',
|
|
||||||
'cal',
|
|
||||||
'capnproto',
|
|
||||||
'clojure',
|
|
||||||
'cmake',
|
|
||||||
'coffeescript',
|
|
||||||
'coq',
|
|
||||||
'cos',
|
|
||||||
'cpp',
|
|
||||||
'crmsh',
|
|
||||||
'crystal',
|
|
||||||
'csharp',
|
|
||||||
'csp',
|
|
||||||
'css',
|
|
||||||
'd',
|
|
||||||
'dart',
|
|
||||||
'diff',
|
|
||||||
'django',
|
|
||||||
'dns',
|
|
||||||
'dockerfile',
|
|
||||||
'dos',
|
|
||||||
'dpr',
|
|
||||||
'dsconfig',
|
|
||||||
'dts',
|
|
||||||
'dust',
|
|
||||||
'ebnf',
|
|
||||||
'elixir',
|
|
||||||
'elm',
|
|
||||||
'erlang',
|
|
||||||
'excel',
|
|
||||||
'fix',
|
|
||||||
'fortran',
|
|
||||||
'fsharp',
|
|
||||||
'gams',
|
|
||||||
'gauss',
|
|
||||||
'gcode',
|
|
||||||
'gherkin',
|
|
||||||
'glsl',
|
|
||||||
'go',
|
|
||||||
'golo',
|
|
||||||
'gradle',
|
|
||||||
'graph',
|
|
||||||
'graphql',
|
|
||||||
'groovy',
|
|
||||||
'haml',
|
|
||||||
'handlebars',
|
|
||||||
'haskell',
|
|
||||||
'haxe',
|
|
||||||
'http',
|
|
||||||
'hy',
|
|
||||||
'inform7',
|
|
||||||
'ini',
|
|
||||||
'irpf90',
|
|
||||||
'java',
|
|
||||||
'javascript',
|
|
||||||
'json',
|
|
||||||
'julia',
|
|
||||||
'k',
|
|
||||||
'kotlin',
|
|
||||||
'lasso',
|
|
||||||
'ldif',
|
|
||||||
'leaf',
|
|
||||||
'less',
|
|
||||||
'lisp',
|
|
||||||
'livecodeserver',
|
|
||||||
'livescript',
|
|
||||||
'lua',
|
|
||||||
'makefile',
|
|
||||||
'markdown',
|
|
||||||
'mathematica',
|
|
||||||
'matlab',
|
|
||||||
'maxima',
|
|
||||||
'mel',
|
|
||||||
'mercury',
|
|
||||||
'mips',
|
|
||||||
'mizar',
|
|
||||||
'mojolicious',
|
|
||||||
'monkey',
|
|
||||||
'moonscript',
|
|
||||||
'n1ql',
|
|
||||||
'nginx',
|
|
||||||
'nim',
|
|
||||||
'nix',
|
|
||||||
'nsis',
|
|
||||||
'objectivec',
|
|
||||||
'ocaml',
|
|
||||||
'openscad',
|
|
||||||
'oxygene',
|
|
||||||
'p21',
|
|
||||||
'parser3',
|
|
||||||
'perl',
|
|
||||||
'pf',
|
|
||||||
'pgsql',
|
|
||||||
'php',
|
|
||||||
'plaintext',
|
|
||||||
'pony',
|
|
||||||
'powershell',
|
|
||||||
'processing',
|
|
||||||
'profile',
|
|
||||||
'prolog',
|
|
||||||
'properties',
|
|
||||||
'protobuf',
|
|
||||||
'puppet',
|
|
||||||
'python',
|
|
||||||
'python-repl',
|
|
||||||
'qml',
|
|
||||||
'r',
|
|
||||||
'reasonml',
|
|
||||||
'rib',
|
|
||||||
'rsl',
|
|
||||||
'ruby',
|
|
||||||
'ruleslanguage',
|
|
||||||
'rust',
|
|
||||||
'SAS',
|
|
||||||
'scala' ,
|
|
||||||
'scheme',
|
|
||||||
'scilab',
|
|
||||||
'scss',
|
|
||||||
'shell',
|
|
||||||
'smali',
|
|
||||||
'smalltalk',
|
|
||||||
'sml',
|
|
||||||
'sql',
|
|
||||||
'stan',
|
|
||||||
'stata',
|
|
||||||
'stylus',
|
|
||||||
'subunit',
|
|
||||||
'swift',
|
|
||||||
'tap',
|
|
||||||
'tcl',
|
|
||||||
'tex',
|
|
||||||
'thrift',
|
|
||||||
'tp',
|
|
||||||
'twig',
|
|
||||||
'typescript',
|
|
||||||
'vala',
|
|
||||||
'vbnet',
|
|
||||||
'vbscript',
|
|
||||||
'verilog',
|
|
||||||
'vhdl',
|
|
||||||
'vim',
|
|
||||||
'x86asm',
|
|
||||||
'xl',
|
|
||||||
'xml',
|
|
||||||
'xquery',
|
|
||||||
'yml',
|
|
||||||
'zephir',
|
|
||||||
]);
|
|
||||||
|
|
||||||
module.exports = languages;
|
|
||||||
|
|
@ -1,46 +0,0 @@
|
||||||
const primaryRegex = /```([^`\n]*?)\n([\s\S]*?)\n```/g;
|
|
||||||
const secondaryRegex = /```([^`\n]*?)\n?([\s\S]*?)\n?```/g;
|
|
||||||
|
|
||||||
const unenclosedCodeTest = (text) => {
|
|
||||||
let workingText = text;
|
|
||||||
// if (workingText.startsWith('<') || (!workingText.startsWith('`') && workingText.match(/```/g)?.length === 1)) {
|
|
||||||
// workingText = `\`\`\`${workingText}`
|
|
||||||
// }
|
|
||||||
|
|
||||||
return workingText.trim();
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function regexSplit(string) {
|
|
||||||
let matches = [...string.matchAll(primaryRegex)];
|
|
||||||
|
|
||||||
if (!matches[0]) {
|
|
||||||
matches = [...string.matchAll(secondaryRegex)];
|
|
||||||
}
|
|
||||||
|
|
||||||
const output = [matches[0].input.slice(0, matches[0].index)];
|
|
||||||
|
|
||||||
// console.log(matches);
|
|
||||||
|
|
||||||
for (let i = 0; i < matches.length; i++) {
|
|
||||||
const [fullMatch, language, code] = matches[i];
|
|
||||||
// const formattedCode = code.replace(/`+/g, '\\`');
|
|
||||||
output.push(`\`\`\`${language}\n${code}\n\`\`\``);
|
|
||||||
if (i < matches.length - 1) {
|
|
||||||
let nextText = string.slice(matches[i].index + fullMatch.length, matches[i + 1].index);
|
|
||||||
nextText = unenclosedCodeTest(nextText);
|
|
||||||
output.push(nextText);
|
|
||||||
} else {
|
|
||||||
const lastMatch = matches[matches.length - 1][0];
|
|
||||||
// console.log(lastMatch);
|
|
||||||
// console.log(matches[0].input.split(lastMatch));
|
|
||||||
let rest = matches[0].input.split(lastMatch)[1]
|
|
||||||
|
|
||||||
if (rest) {
|
|
||||||
rest = unenclosedCodeTest(rest);
|
|
||||||
output.push(rest);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
14
api/package-lock.json
generated
14
api/package-lock.json
generated
|
|
@ -10,7 +10,6 @@
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@keyv/mongo": "^2.1.8",
|
"@keyv/mongo": "^2.1.8",
|
||||||
"@vscode/vscode-languagedetection": "^1.0.22",
|
|
||||||
"@waylaidwanderer/chatgpt-api": "^1.32.8",
|
"@waylaidwanderer/chatgpt-api": "^1.32.8",
|
||||||
"axios": "^1.3.4",
|
"axios": "^1.3.4",
|
||||||
"chatgpt-latest": "npm:@waylaidwanderer/chatgpt-api@^1.31.6",
|
"chatgpt-latest": "npm:@waylaidwanderer/chatgpt-api@^1.31.6",
|
||||||
|
|
@ -1626,14 +1625,6 @@
|
||||||
"@types/webidl-conversions": "*"
|
"@types/webidl-conversions": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vscode/vscode-languagedetection": {
|
|
||||||
"version": "1.0.22",
|
|
||||||
"resolved": "https://registry.npmjs.org/@vscode/vscode-languagedetection/-/vscode-languagedetection-1.0.22.tgz",
|
|
||||||
"integrity": "sha512-rQ/BgMyLuIXSmbA0MSkIPHtcOw14QkeDbAq19sjvaS9LTRr905yij0S8lsyqN5JgOsbtIx7pAcyOxFMzPmqhZQ==",
|
|
||||||
"bin": {
|
|
||||||
"vscode-languagedetection": "cli/index.js"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@waylaidwanderer/chatgpt-api": {
|
"node_modules/@waylaidwanderer/chatgpt-api": {
|
||||||
"version": "1.32.8",
|
"version": "1.32.8",
|
||||||
"resolved": "https://registry.npmjs.org/@waylaidwanderer/chatgpt-api/-/chatgpt-api-1.32.8.tgz",
|
"resolved": "https://registry.npmjs.org/@waylaidwanderer/chatgpt-api/-/chatgpt-api-1.32.8.tgz",
|
||||||
|
|
@ -6977,11 +6968,6 @@
|
||||||
"@types/webidl-conversions": "*"
|
"@types/webidl-conversions": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@vscode/vscode-languagedetection": {
|
|
||||||
"version": "1.0.22",
|
|
||||||
"resolved": "https://registry.npmjs.org/@vscode/vscode-languagedetection/-/vscode-languagedetection-1.0.22.tgz",
|
|
||||||
"integrity": "sha512-rQ/BgMyLuIXSmbA0MSkIPHtcOw14QkeDbAq19sjvaS9LTRr905yij0S8lsyqN5JgOsbtIx7pAcyOxFMzPmqhZQ=="
|
|
||||||
},
|
|
||||||
"@waylaidwanderer/chatgpt-api": {
|
"@waylaidwanderer/chatgpt-api": {
|
||||||
"version": "1.32.8",
|
"version": "1.32.8",
|
||||||
"resolved": "https://registry.npmjs.org/@waylaidwanderer/chatgpt-api/-/chatgpt-api-1.32.8.tgz",
|
"resolved": "https://registry.npmjs.org/@waylaidwanderer/chatgpt-api/-/chatgpt-api-1.32.8.tgz",
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@
|
||||||
"homepage": "https://github.com/danny-avila/chatgpt-clone#readme",
|
"homepage": "https://github.com/danny-avila/chatgpt-clone#readme",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@keyv/mongo": "^2.1.8",
|
"@keyv/mongo": "^2.1.8",
|
||||||
"@vscode/vscode-languagedetection": "^1.0.22",
|
|
||||||
"@waylaidwanderer/chatgpt-api": "^1.32.8",
|
"@waylaidwanderer/chatgpt-api": "^1.32.8",
|
||||||
"axios": "^1.3.4",
|
"axios": "^1.3.4",
|
||||||
"chatgpt-latest": "npm:@waylaidwanderer/chatgpt-api@^1.31.6",
|
"chatgpt-latest": "npm:@waylaidwanderer/chatgpt-api@^1.31.6",
|
||||||
|
|
|
||||||
51
client/package-lock.json
generated
51
client/package-lock.json
generated
|
|
@ -19,13 +19,10 @@
|
||||||
"class-variance-authority": "^0.4.0",
|
"class-variance-authority": "^0.4.0",
|
||||||
"clsx": "^1.2.1",
|
"clsx": "^1.2.1",
|
||||||
"crypto-browserify": "^3.12.0",
|
"crypto-browserify": "^3.12.0",
|
||||||
"highlight.js": "^11.7.0",
|
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"lucide-react": "^0.113.0",
|
"lucide-react": "^0.113.0",
|
||||||
"markdown-to-jsx": "^7.1.9",
|
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-highlight": "^0.15.0",
|
|
||||||
"react-lazy-load": "^4.0.1",
|
"react-lazy-load": "^4.0.1",
|
||||||
"react-markdown": "^8.0.5",
|
"react-markdown": "^8.0.5",
|
||||||
"react-redux": "^8.0.5",
|
"react-redux": "^8.0.5",
|
||||||
|
|
@ -7941,17 +7938,6 @@
|
||||||
"url": "https://github.com/sponsors/wooorm"
|
"url": "https://github.com/sponsors/wooorm"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/markdown-to-jsx": {
|
|
||||||
"version": "7.1.9",
|
|
||||||
"resolved": "https://registry.npmjs.org/markdown-to-jsx/-/markdown-to-jsx-7.1.9.tgz",
|
|
||||||
"integrity": "sha512-x4STVIKIJR0mGgZIZ5RyAeQD7FEZd5tS8m/htbcVGlex32J+hlSLj+ExrHCxP6nRKF1EKbcO7i6WhC1GtOpBlA==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 10"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"react": ">= 0.14.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/md5.js": {
|
"node_modules/md5.js": {
|
||||||
"version": "1.3.5",
|
"version": "1.3.5",
|
||||||
"resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
|
"resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
|
||||||
|
|
@ -10591,22 +10577,6 @@
|
||||||
"react": "^18.2.0"
|
"react": "^18.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-highlight": {
|
|
||||||
"version": "0.15.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/react-highlight/-/react-highlight-0.15.0.tgz",
|
|
||||||
"integrity": "sha512-5uV/b/N4Z421GSVVe05fz+OfTsJtFzx/fJBdafZyw4LS70XjIZwgEx3Lrkfc01W/RzZ2Dtfb0DApoaJFAIKBtA==",
|
|
||||||
"dependencies": {
|
|
||||||
"highlight.js": "^10.5.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/react-highlight/node_modules/highlight.js": {
|
|
||||||
"version": "10.7.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz",
|
|
||||||
"integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==",
|
|
||||||
"engines": {
|
|
||||||
"node": "*"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/react-is": {
|
"node_modules/react-is": {
|
||||||
"version": "16.13.1",
|
"version": "16.13.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||||
|
|
@ -18976,12 +18946,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.3.tgz",
|
||||||
"integrity": "sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw=="
|
"integrity": "sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw=="
|
||||||
},
|
},
|
||||||
"markdown-to-jsx": {
|
|
||||||
"version": "7.1.9",
|
|
||||||
"resolved": "https://registry.npmjs.org/markdown-to-jsx/-/markdown-to-jsx-7.1.9.tgz",
|
|
||||||
"integrity": "sha512-x4STVIKIJR0mGgZIZ5RyAeQD7FEZd5tS8m/htbcVGlex32J+hlSLj+ExrHCxP6nRKF1EKbcO7i6WhC1GtOpBlA==",
|
|
||||||
"requires": {}
|
|
||||||
},
|
|
||||||
"md5.js": {
|
"md5.js": {
|
||||||
"version": "1.3.5",
|
"version": "1.3.5",
|
||||||
"resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
|
"resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
|
||||||
|
|
@ -20638,21 +20602,6 @@
|
||||||
"scheduler": "^0.23.0"
|
"scheduler": "^0.23.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"react-highlight": {
|
|
||||||
"version": "0.15.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/react-highlight/-/react-highlight-0.15.0.tgz",
|
|
||||||
"integrity": "sha512-5uV/b/N4Z421GSVVe05fz+OfTsJtFzx/fJBdafZyw4LS70XjIZwgEx3Lrkfc01W/RzZ2Dtfb0DApoaJFAIKBtA==",
|
|
||||||
"requires": {
|
|
||||||
"highlight.js": "^10.5.0"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"highlight.js": {
|
|
||||||
"version": "10.7.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz",
|
|
||||||
"integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A=="
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"react-is": {
|
"react-is": {
|
||||||
"version": "16.13.1",
|
"version": "16.13.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||||
|
|
|
||||||
|
|
@ -29,13 +29,10 @@
|
||||||
"class-variance-authority": "^0.4.0",
|
"class-variance-authority": "^0.4.0",
|
||||||
"clsx": "^1.2.1",
|
"clsx": "^1.2.1",
|
||||||
"crypto-browserify": "^3.12.0",
|
"crypto-browserify": "^3.12.0",
|
||||||
"highlight.js": "^11.7.0",
|
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"lucide-react": "^0.113.0",
|
"lucide-react": "^0.113.0",
|
||||||
"markdown-to-jsx": "^7.1.9",
|
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-highlight": "^0.15.0",
|
|
||||||
"react-lazy-load": "^4.0.1",
|
"react-lazy-load": "^4.0.1",
|
||||||
"react-markdown": "^8.0.5",
|
"react-markdown": "^8.0.5",
|
||||||
"react-redux": "^8.0.5",
|
"react-redux": "^8.0.5",
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import rehypeRaw from 'rehype-raw'
|
||||||
import CodeBlock from './CodeBlock';
|
import CodeBlock from './CodeBlock';
|
||||||
import { langSubset } from '~/utils/languages';
|
import { langSubset } from '~/utils/languages';
|
||||||
|
|
||||||
const Content = React.memo(({ content, isCreatedByUser = true }) => {
|
const Content = React.memo(({ content }) => {
|
||||||
let rehypePlugins = [
|
let rehypePlugins = [
|
||||||
[rehypeKatex, { output: 'mathml' }],
|
[rehypeKatex, { output: 'mathml' }],
|
||||||
[
|
[
|
||||||
|
|
@ -22,23 +22,19 @@ const Content = React.memo(({ content, isCreatedByUser = true }) => {
|
||||||
[rehypeRaw],
|
[rehypeRaw],
|
||||||
];
|
];
|
||||||
|
|
||||||
rehypePlugins = isCreatedByUser ? rehypePlugins.slice(0, -1) : rehypePlugins;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<ReactMarkdown
|
||||||
<ReactMarkdown
|
remarkPlugins={[remarkGfm, [remarkMath, { singleDollarTextMath: false }]]}
|
||||||
remarkPlugins={[remarkGfm, [remarkMath, { singleDollarTextMath: false }]]}
|
rehypePlugins={rehypePlugins}
|
||||||
rehypePlugins={rehypePlugins}
|
linkTarget="_new"
|
||||||
linkTarget="_new"
|
components={{
|
||||||
components={{
|
code,
|
||||||
code,
|
p,
|
||||||
p,
|
// em,
|
||||||
// em,
|
}}
|
||||||
}}
|
>
|
||||||
>
|
{content}
|
||||||
{content}
|
</ReactMarkdown>
|
||||||
</ReactMarkdown>
|
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,37 +0,0 @@
|
||||||
import React, { useState } from 'react';
|
|
||||||
import Clipboard from '~/components/svg/Clipboard';
|
|
||||||
import CheckMark from '~/components/svg/CheckMark';
|
|
||||||
|
|
||||||
const Embed = React.memo(({ children, lang = '', code, matched }) => {
|
|
||||||
const [buttonText, setButtonText] = useState('Copy code');
|
|
||||||
const isClicked = buttonText === 'Copy code';
|
|
||||||
|
|
||||||
const clickHandler = () => {
|
|
||||||
navigator.clipboard.writeText(code.trim());
|
|
||||||
setButtonText('Copied!');
|
|
||||||
setTimeout(() => {
|
|
||||||
setButtonText('Copy code');
|
|
||||||
}, 3000);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<pre>
|
|
||||||
<div className="mb-4 rounded-md bg-black">
|
|
||||||
<div className="relative flex items-center rounded-tl-md rounded-tr-md bg-gray-800 px-4 py-2 font-sans text-xs text-gray-200">
|
|
||||||
<span className="">{lang === 'javascript' && !matched ? '' : lang}</span>
|
|
||||||
<button
|
|
||||||
className="ml-auto flex gap-2"
|
|
||||||
onClick={clickHandler}
|
|
||||||
disabled={!isClicked}
|
|
||||||
>
|
|
||||||
{isClicked ? <Clipboard /> : <CheckMark />}
|
|
||||||
{buttonText}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div className="overflow-y-auto p-4">{children}</div>
|
|
||||||
</div>
|
|
||||||
</pre>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
export default Embed;
|
|
||||||
|
|
@ -1,32 +0,0 @@
|
||||||
import React, { useState, useEffect } from 'react';
|
|
||||||
import Highlighter from 'react-highlight';
|
|
||||||
import hljs from 'highlight.js';
|
|
||||||
import { languages } from '~/utils/languages';
|
|
||||||
|
|
||||||
const Highlight = React.memo(({ language, code }) => {
|
|
||||||
const [highlightedCode, setHighlightedCode] = useState(code);
|
|
||||||
const lang = languages.has(language) ? language : 'javascript';
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setHighlightedCode(hljs.highlight(code, { language: lang }).value);
|
|
||||||
}, [code, lang]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<pre>
|
|
||||||
{!highlightedCode ? (
|
|
||||||
// <code className={`hljs !whitespace-pre language-${lang ? lang: 'javascript'}`}>
|
|
||||||
<Highlighter className={`hljs !whitespace-pre language-${lang ? lang : 'javascript'}`}>
|
|
||||||
{code}
|
|
||||||
</Highlighter>
|
|
||||||
) : (
|
|
||||||
<code
|
|
||||||
className={`hljs language-${lang}`}
|
|
||||||
dangerouslySetInnerHTML={{ __html: highlightedCode }}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</pre>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
export default Highlight;
|
|
||||||
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
export default function TabLink(a) {
|
|
||||||
return (
|
|
||||||
<a
|
|
||||||
href={a.href}
|
|
||||||
title={a.title}
|
|
||||||
className={a.className}
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>
|
|
||||||
{a.children}
|
|
||||||
</a>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -1,162 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import TabLink from './TabLink';
|
|
||||||
import Markdown from 'markdown-to-jsx';
|
|
||||||
import Embed from './Embed';
|
|
||||||
import Highlight from './Highlight';
|
|
||||||
import regexSplit from '~/utils/regexSplit';
|
|
||||||
import { wrapperRegex } from '~/utils';
|
|
||||||
const { codeRegex, inLineRegex, markupRegex, languageMatch, newLineMatch } = wrapperRegex;
|
|
||||||
const mdOptions = {
|
|
||||||
wrapper: React.Fragment,
|
|
||||||
forceWrapper: true,
|
|
||||||
overrides: {
|
|
||||||
a: {
|
|
||||||
component: TabLink,
|
|
||||||
// props: {
|
|
||||||
// className: 'foo'
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const inLineWrap = (parts) => {
|
|
||||||
let previousElement = null;
|
|
||||||
return parts.map((part, i) => {
|
|
||||||
if (part.match(markupRegex)) {
|
|
||||||
const codeElement = <code key={i}>{part.slice(1, -1)}</code>;
|
|
||||||
if (previousElement && typeof previousElement !== 'string') {
|
|
||||||
// Append code element as a child to previous non-code element
|
|
||||||
previousElement = (
|
|
||||||
<Markdown
|
|
||||||
options={mdOptions}
|
|
||||||
key={i}
|
|
||||||
>
|
|
||||||
{previousElement}
|
|
||||||
{codeElement}
|
|
||||||
</Markdown>
|
|
||||||
);
|
|
||||||
return previousElement;
|
|
||||||
} else {
|
|
||||||
return codeElement;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
previousElement = part;
|
|
||||||
return previousElement;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
function TextWrapper({ text, generateCursor }) {
|
|
||||||
let embedTest = false;
|
|
||||||
let result = null;
|
|
||||||
|
|
||||||
// to match unenclosed code blocks
|
|
||||||
if (text.match(/```/g)?.length === 1) {
|
|
||||||
embedTest = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// match enclosed code blocks
|
|
||||||
if (text.match(codeRegex)) {
|
|
||||||
const parts = regexSplit(text);
|
|
||||||
// console.log(parts);
|
|
||||||
const codeParts = parts.map((part, i) => {
|
|
||||||
if (part.match(codeRegex)) {
|
|
||||||
let language = 'javascript';
|
|
||||||
let matched = false;
|
|
||||||
|
|
||||||
if (part.match(languageMatch)) {
|
|
||||||
language = part.match(languageMatch)[1].toLowerCase();
|
|
||||||
part = part.replace(languageMatch, '```');
|
|
||||||
matched = true;
|
|
||||||
// highlight.js language validation
|
|
||||||
// const validLanguage = languages.some((lang) => language === lang);
|
|
||||||
// part = validLanguage ? part.replace(languageMatch, '```') : part;
|
|
||||||
// language = validLanguage ? language : 'javascript';
|
|
||||||
}
|
|
||||||
|
|
||||||
part = part.replace(newLineMatch, '```');
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Embed
|
|
||||||
key={i}
|
|
||||||
language={language}
|
|
||||||
code={part.slice(3, -3)}
|
|
||||||
matched={matched}
|
|
||||||
>
|
|
||||||
<Highlight
|
|
||||||
language={language}
|
|
||||||
code={part.slice(3, -3)}
|
|
||||||
/>
|
|
||||||
</Embed>
|
|
||||||
);
|
|
||||||
} else if (part.match(inLineRegex)) {
|
|
||||||
const innerParts = part.split(inLineRegex);
|
|
||||||
return inLineWrap(innerParts);
|
|
||||||
} else {
|
|
||||||
return (
|
|
||||||
<Markdown
|
|
||||||
options={mdOptions}
|
|
||||||
key={i}
|
|
||||||
>
|
|
||||||
{part}
|
|
||||||
</Markdown>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return <>{codeParts}</>; // return the wrapped text
|
|
||||||
} else if (embedTest) {
|
|
||||||
const language = text.match(/```(\w+)/)?.[1].toLowerCase() || 'javascript';
|
|
||||||
const parts = text.split(text.match(/```(\w+)/)?.[0] || '```');
|
|
||||||
const codeParts = parts.map((part, i) => {
|
|
||||||
if (i === 1) {
|
|
||||||
part = part.replace(/^\n+/, '');
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Embed
|
|
||||||
key={i}
|
|
||||||
language={language}
|
|
||||||
>
|
|
||||||
<Highlight
|
|
||||||
code={part}
|
|
||||||
language={language}
|
|
||||||
/>
|
|
||||||
</Embed>
|
|
||||||
);
|
|
||||||
} else if (part.match(inLineRegex)) {
|
|
||||||
const innerParts = part.split(inLineRegex);
|
|
||||||
return inLineWrap(innerParts);
|
|
||||||
} else {
|
|
||||||
return (
|
|
||||||
<Markdown
|
|
||||||
options={mdOptions}
|
|
||||||
key={i}
|
|
||||||
>
|
|
||||||
{part}
|
|
||||||
</Markdown>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// return <>{codeParts}</>; // return the wrapped text
|
|
||||||
result = <>{codeParts}</>;
|
|
||||||
} else if (text.match(markupRegex)) {
|
|
||||||
// map over the parts and wrap any text between tildes with <code> tags
|
|
||||||
const parts = text.split(markupRegex);
|
|
||||||
const codeParts = inLineWrap(parts);
|
|
||||||
// return <>{codeParts}</>; // return the wrapped text
|
|
||||||
result = <>{codeParts}</>;
|
|
||||||
} else {
|
|
||||||
// return <Markdown options={mdOptions}>{text}</Markdown>;
|
|
||||||
result = <Markdown options={mdOptions}>{text}</Markdown>;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{result}
|
|
||||||
{generateCursor()}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default React.memo(TextWrapper);
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import TextWrapper from './TextWrapper';
|
|
||||||
import Content from './Content';
|
|
||||||
|
|
||||||
const Wrapper = React.memo(({ text, generateCursor, isCreatedByUser, searchResult }) => {
|
|
||||||
if (searchResult) {
|
|
||||||
return (
|
|
||||||
<Content
|
|
||||||
content={text}
|
|
||||||
isCreatedByUser={isCreatedByUser}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
} else if (!isCreatedByUser) {
|
|
||||||
return (
|
|
||||||
<TextWrapper
|
|
||||||
text={text}
|
|
||||||
generateCursor={generateCursor}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
} else if (isCreatedByUser) {
|
|
||||||
return <>{text}</>;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export default Wrapper;
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import React, { useState, useEffect, useRef, useCallback } from 'react';
|
import React, { useState, useEffect, useRef, useCallback } from 'react';
|
||||||
import { useSelector, useDispatch } from 'react-redux';
|
import { useSelector, useDispatch } from 'react-redux';
|
||||||
import SubRow from './Content/SubRow';
|
import SubRow from './Content/SubRow';
|
||||||
import Wrapper from './Content/Wrapper';
|
import Content from './Content/Content';
|
||||||
import MultiMessage from './MultiMessage';
|
import MultiMessage from './MultiMessage';
|
||||||
import HoverButtons from './HoverButtons';
|
import HoverButtons from './HoverButtons';
|
||||||
import SiblingSwitch from './SiblingSwitch';
|
import SiblingSwitch from './SiblingSwitch';
|
||||||
|
|
@ -199,12 +199,17 @@ export default function Message({
|
||||||
<div className="flex min-h-[20px] flex-grow flex-col items-start gap-4 whitespace-pre-wrap">
|
<div className="flex min-h-[20px] flex-grow flex-col items-start gap-4 whitespace-pre-wrap">
|
||||||
{/* <div className={`${blinker ? 'result-streaming' : ''} markdown prose dark:prose-invert light w-full break-words`}> */}
|
{/* <div className={`${blinker ? 'result-streaming' : ''} markdown prose dark:prose-invert light w-full break-words`}> */}
|
||||||
<div className="markdown prose dark:prose-invert light w-full break-words">
|
<div className="markdown prose dark:prose-invert light w-full break-words">
|
||||||
<Wrapper
|
{!isCreatedByUser ?
|
||||||
text={text}
|
<>
|
||||||
generateCursor={generateCursor}
|
<Content
|
||||||
isCreatedByUser={isCreatedByUser}
|
content={text}
|
||||||
searchResult={searchResult}
|
/>
|
||||||
/>
|
{generateCursor()}
|
||||||
|
</> :
|
||||||
|
<>
|
||||||
|
{text}
|
||||||
|
</>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -38,14 +38,6 @@ export const languages = [
|
||||||
'pascal'
|
'pascal'
|
||||||
];
|
];
|
||||||
|
|
||||||
export const wrapperRegex = {
|
|
||||||
codeRegex: /(```[\s\S]*?```)/g,
|
|
||||||
inLineRegex: /(`[^`]+?`)/g,
|
|
||||||
markupRegex: /(`[^`]+?`)/g,
|
|
||||||
languageMatch: /^```(\w+)/,
|
|
||||||
newLineMatch: /^```(\n+)/
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getIconOfModel = ({ size=30, sender, isCreatedByUser, searchResult, model, chatGptLabel, error, ...props }) => {
|
export const getIconOfModel = ({ size=30, sender, isCreatedByUser, searchResult, model, chatGptLabel, error, ...props }) => {
|
||||||
// 'ai' is used as 'model' is not accurate for search results
|
// 'ai' is used as 'model' is not accurate for search results
|
||||||
let ai = searchResult ? sender : model;
|
let ai = searchResult ? sender : model;
|
||||||
|
|
|
||||||
|
|
@ -1,46 +0,0 @@
|
||||||
const primaryRegex = /```([^`\n]*?)\n([\s\S]*?)\n```/g;
|
|
||||||
const secondaryRegex = /```([^`\n]*?)\n?([\s\S]*?)\n?```/g;
|
|
||||||
|
|
||||||
const unenclosedCodeTest = (text) => {
|
|
||||||
let workingText = text;
|
|
||||||
// if (workingText.startsWith('<') || (!workingText.startsWith('`') && workingText.match(/```/g)?.length === 1)) {
|
|
||||||
// workingText = `\`\`\`${workingText}`
|
|
||||||
// }
|
|
||||||
|
|
||||||
return workingText.trim();
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function regexSplit(string) {
|
|
||||||
let matches = [...string.matchAll(primaryRegex)];
|
|
||||||
|
|
||||||
if (!matches[0]) {
|
|
||||||
matches = [...string.matchAll(secondaryRegex)];
|
|
||||||
}
|
|
||||||
|
|
||||||
const output = [matches[0].input.slice(0, matches[0].index)];
|
|
||||||
|
|
||||||
// console.log(matches);
|
|
||||||
|
|
||||||
for (let i = 0; i < matches.length; i++) {
|
|
||||||
const [fullMatch, language, code] = matches[i];
|
|
||||||
// const formattedCode = code.replace(/`+/g, '\\`');
|
|
||||||
output.push(`\`\`\`${language}\n${code}\n\`\`\``);
|
|
||||||
if (i < matches.length - 1) {
|
|
||||||
let nextText = string.slice(matches[i].index + fullMatch.length, matches[i + 1].index);
|
|
||||||
nextText = unenclosedCodeTest(nextText);
|
|
||||||
output.push(nextText);
|
|
||||||
} else {
|
|
||||||
const lastMatch = matches[matches.length - 1][0];
|
|
||||||
// console.log(lastMatch);
|
|
||||||
// console.log(matches[0].input.split(lastMatch));
|
|
||||||
let rest = matches[0].input.split(lastMatch)[1]
|
|
||||||
|
|
||||||
if (rest) {
|
|
||||||
rest = unenclosedCodeTest(rest);
|
|
||||||
output.push(rest);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue