mirror of
https://github.com/philomena-dev/philomena.git
synced 2024-11-23 20:18:00 +01:00
Integrate Eslint and TypeScript into build & linting process (#142)
This commit is contained in:
parent
0487a82db6
commit
77e689e29a
23 changed files with 2002 additions and 133 deletions
28
.github/workflows/elixir.yml
vendored
28
.github/workflows/elixir.yml
vendored
|
@ -8,7 +8,8 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- uses: actions/cache@v2
|
||||
- name: Cache mix deps
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
_build
|
||||
|
@ -25,3 +26,28 @@ jobs:
|
|||
run: |
|
||||
docker-compose run app mix sobelow --config
|
||||
docker-compose run app mix deps.audit
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: '14'
|
||||
|
||||
- name: Cache node_modules
|
||||
id: cache-node-modules
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ./assets/node_modules
|
||||
key: node_modules-${{ hashFiles('./assets/package-lock.json') }}
|
||||
|
||||
- name: Install npm dependencies
|
||||
if: steps.cache-node-modules.outputs.cache-hit != 'true'
|
||||
run: npm ci --ignore-scripts
|
||||
working-directory: ./assets
|
||||
|
||||
- name: Run ESLint
|
||||
run: npm run lint
|
||||
working-directory: ./assets
|
||||
|
|
2
assets/.eslintignore
Normal file
2
assets/.eslintignore
Normal file
|
@ -0,0 +1,2 @@
|
|||
js/vendor/*
|
||||
webpack.config.js
|
|
@ -2,16 +2,24 @@ env:
|
|||
browser: true
|
||||
es6: true
|
||||
|
||||
parser: '@typescript-eslint/parser'
|
||||
|
||||
parserOptions:
|
||||
ecmaVersion: 6
|
||||
sourceType: module
|
||||
|
||||
plugins:
|
||||
- '@typescript-eslint'
|
||||
|
||||
globals:
|
||||
ga: false
|
||||
md5: false
|
||||
Sortable: false
|
||||
ActionCable: false
|
||||
|
||||
extends:
|
||||
- 'plugin:@typescript-eslint/recommended'
|
||||
|
||||
rules:
|
||||
accessor-pairs: 2
|
||||
array-bracket-spacing: 0
|
||||
|
@ -83,7 +91,6 @@ rules:
|
|||
no-console: 0
|
||||
no-const-assign: 2
|
||||
no-constant-condition: 2
|
||||
no-continue: 2
|
||||
no-control-regex: 2
|
||||
no-debugger: 2
|
||||
no-delete-var: 2
|
||||
|
@ -245,3 +252,10 @@ rules:
|
|||
wrap-regex: 0
|
||||
yield-star-spacing: 2
|
||||
yoda: [2, 'never']
|
||||
|
||||
# Disable rules which are impossible to satisfy (types require .ts extension)
|
||||
overrides:
|
||||
- files:
|
||||
- '*.js'
|
||||
rules:
|
||||
'@typescript-eslint/explicit-module-boundary-types': 0
|
|
@ -1,2 +0,0 @@
|
|||
vendor/*
|
||||
match_query.js
|
|
@ -81,7 +81,8 @@ function initializeFilters() {
|
|||
}
|
||||
|
||||
function unmarshal(data) {
|
||||
try { return JSON.parse(data); } catch (_) { return data; }
|
||||
try { return JSON.parse(data); }
|
||||
catch (_) { return data; }
|
||||
}
|
||||
|
||||
function loadBooruData() {
|
||||
|
|
|
@ -31,14 +31,16 @@ const actions = {
|
|||
|
||||
disable(data) { selectorCb(data.base, data.value, el => el.disabled = true); },
|
||||
|
||||
copy(data) { document.querySelector(data.value).select();
|
||||
document.execCommand('copy'); },
|
||||
copy(data) {
|
||||
document.querySelector(data.value).select();
|
||||
document.execCommand('copy');
|
||||
},
|
||||
|
||||
inputvalue(data) { document.querySelector(data.value).value = data.el.dataset.setValue; },
|
||||
|
||||
selectvalue(data) { document.querySelector(data.value).value = data.el.querySelector(':checked').dataset.setValue; },
|
||||
|
||||
checkall(data) { $$(`${data.value} input[type=checkbox]`).forEach(c => { c.checked = !c.checked; }) },
|
||||
checkall(data) { $$(`${data.value} input[type=checkbox]`).forEach(c => { c.checked = !c.checked; }); },
|
||||
|
||||
focus(data) { document.querySelector(data.value).focus(); },
|
||||
|
||||
|
@ -50,8 +52,8 @@ const actions = {
|
|||
|
||||
tab(data) {
|
||||
const block = data.el.parentNode.parentNode,
|
||||
newTab = $(`.block__tab[data-tab="${data.value}"]`),
|
||||
loadTab = data.el.dataset.loadTab;
|
||||
newTab = $(`.block__tab[data-tab="${data.value}"]`),
|
||||
loadTab = data.el.dataset.loadTab;
|
||||
|
||||
// Switch tab
|
||||
const selectedTab = block.querySelector('.selected');
|
||||
|
@ -100,8 +102,8 @@ function matchAttributes(event) {
|
|||
for (const action in actions) {
|
||||
|
||||
const attr = `data-${event.type}-${action.toLowerCase()}`,
|
||||
el = event.target && event.target.closest(`[${attr}]`),
|
||||
value = el && el.getAttribute(attr);
|
||||
el = event.target && event.target.closest(`[${attr}]`),
|
||||
value = el && el.getAttribute(attr);
|
||||
|
||||
if (el) {
|
||||
// Return true if you don't want to preventDefault
|
||||
|
|
|
@ -30,10 +30,12 @@ function commentPosted(response) {
|
|||
|
||||
if (requestOk) {
|
||||
response.text().then(text => {
|
||||
if (text.includes('<div class="flash flash--warning">'))
|
||||
if (text.includes('<div class="flash flash--warning">')) {
|
||||
window.location.reload();
|
||||
else
|
||||
}
|
||||
else {
|
||||
displayComments(container, text);
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -47,9 +47,8 @@ function selectVersion(imageWidth, imageHeight, imageSize, imageMime) {
|
|||
if (imageMime === 'video/webm' || imageSize <= 26214400) {
|
||||
return 'full';
|
||||
}
|
||||
else {
|
||||
return 'large';
|
||||
}
|
||||
|
||||
return 'large';
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -6,9 +6,9 @@ import { fetchJson } from './utils/requests';
|
|||
import { $ } from './utils/dom';
|
||||
|
||||
const endpoints = {
|
||||
vote(imageId) { return `/images/${imageId}/vote` },
|
||||
fave(imageId) { return `/images/${imageId}/fave` },
|
||||
hide(imageId) { return `/images/${imageId}/hide` },
|
||||
vote(imageId) { return `/images/${imageId}/vote`; },
|
||||
fave(imageId) { return `/images/${imageId}/fave`; },
|
||||
hide(imageId) { return `/images/${imageId}/hide`; },
|
||||
};
|
||||
|
||||
const spoilerDownvoteMsg =
|
||||
|
@ -34,16 +34,16 @@ function modifyCache(callback) {
|
|||
cacheEl.value = JSON.stringify(callback(JSON.parse(cacheEl.value)));
|
||||
}
|
||||
|
||||
function cacheStatus(image_id, interaction_type, value) {
|
||||
function cacheStatus(imageId, interactionType, value) {
|
||||
modifyCache(cache => {
|
||||
cache[`${image_id}${interaction_type}`] = { image_id, interaction_type, value };
|
||||
cache[`${imageId}${interactionType}`] = { imageId, interactionType, value };
|
||||
return cache;
|
||||
});
|
||||
}
|
||||
|
||||
function uncacheStatus(image_id, interaction_type) {
|
||||
function uncacheStatus(imageId, interactionType) {
|
||||
modifyCache(cache => {
|
||||
delete cache[`${image_id}${interaction_type}`];
|
||||
delete cache[`${imageId}${interactionType}`];
|
||||
return cache;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -168,7 +168,7 @@ function wrapSelection(textarea, options) {
|
|||
});
|
||||
}
|
||||
|
||||
newText = prefix + newText + suffix
|
||||
newText = prefix + newText + suffix;
|
||||
|
||||
return {
|
||||
newText,
|
||||
|
@ -188,7 +188,7 @@ function wrapLines(textarea, options, eachLine = true) {
|
|||
: text.split(/\n/g).map(line => prefix + line.trim() + suffix).join('\n');
|
||||
|
||||
// Force a space at the end of lines with only blockquote markers
|
||||
newText = newText.replace(/^((?:>\s+)*)>$/gm, '$1> ')
|
||||
newText = newText.replace(/^((?:>\s+)*)>$/gm, '$1> ');
|
||||
|
||||
return { newText, caretOffset: emptyText ? prefix.length : newText.length };
|
||||
}, eachLine);
|
||||
|
|
|
@ -5,18 +5,18 @@
|
|||
|
||||
const tokenList = [
|
||||
['fuzz', /^~(?:\d+(\.\d+)?|\.\d+)/],
|
||||
['boost', /^\^[\-\+]?\d+(\.\d+)?/],
|
||||
['quoted_lit', /^\s*"(?:(?:[^"]|\\")+)"/],
|
||||
['boost', /^\^[-+]?\d+(\.\d+)?/],
|
||||
['quoted_lit', /^\s*"(?:[^"]|\\")+"/],
|
||||
['lparen', /^\s*\(\s*/],
|
||||
['rparen', /^\s*\)\s*/],
|
||||
['and_op', /^\s*(?:\&\&|AND)\s+/],
|
||||
['and_op', /^\s*(?:&&|AND)\s+/],
|
||||
['and_op', /^\s*,\s*/],
|
||||
['or_op', /^\s*(?:\|\||OR)\s+/],
|
||||
['not_op', /^\s*NOT(?:\s+|(?=\())/],
|
||||
['not_op', /^\s*[\!\-]\s*/],
|
||||
['not_op', /^\s*[!-]\s*/],
|
||||
['space', /^\s+/],
|
||||
['word', /^(?:[^\s,\(\)\^~]|\\[\s,\(\)\^~])+/],
|
||||
['word', /^(?:[^\s,\(\)]|\\[\s,\(\)])+/]
|
||||
['word', /^(?:[^\s,()^~]|\\[\s,()^~])+/],
|
||||
['word', /^(?:[^\s,()]|\\[\s,()])+/]
|
||||
],
|
||||
numberFields = ['id', 'width', 'height', 'aspect_ratio',
|
||||
'comment_count', 'score', 'upvotes', 'downvotes',
|
||||
|
@ -35,6 +35,7 @@ const tokenList = [
|
|||
id: 'data-image-id',
|
||||
width: 'data-width',
|
||||
height: 'data-height',
|
||||
/* eslint-disable camelcase */
|
||||
aspect_ratio: 'data-aspect-ratio',
|
||||
comment_count: 'data-comment-count',
|
||||
tag_count: 'data-tag-count',
|
||||
|
@ -43,10 +44,11 @@ const tokenList = [
|
|||
sha512_hash: 'data-sha512',
|
||||
orig_sha512_hash: 'data-orig-sha512',
|
||||
created_at: 'data-created-at'
|
||||
/* eslint-enable camelcase */
|
||||
};
|
||||
|
||||
|
||||
function SearchTerm(termStr, options) {
|
||||
function SearchTerm(termStr) {
|
||||
this.term = termStr.trim();
|
||||
this.parsed = false;
|
||||
}
|
||||
|
@ -57,8 +59,6 @@ SearchTerm.prototype.append = function(substr) {
|
|||
};
|
||||
|
||||
SearchTerm.prototype.parseRangeField = function(field) {
|
||||
let qual;
|
||||
|
||||
if (numberFields.indexOf(field) !== -1) {
|
||||
return [field, 'eq', 'number'];
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ SearchTerm.prototype.parseRangeField = function(field) {
|
|||
return [field, 'eq', 'date'];
|
||||
}
|
||||
|
||||
qual = /^(\w+)\.([lg]te?|eq)$/.exec(field);
|
||||
const qual = /^(\w+)\.([lg]te?|eq)$/.exec(field);
|
||||
|
||||
if (qual) {
|
||||
if (numberFields.indexOf(qual[1]) !== -1) {
|
||||
|
@ -116,28 +116,29 @@ SearchTerm.prototype.parseRelativeDate = function(dateVal, qual) {
|
|||
}
|
||||
}
|
||||
else {
|
||||
throw `Cannot parse date string: ${dateVal}`;
|
||||
throw new Error(`Cannot parse date string: ${dateVal}`);
|
||||
}
|
||||
};
|
||||
|
||||
SearchTerm.prototype.parseAbsoluteDate = function(dateVal, qual) {
|
||||
let parseRes = [
|
||||
/^(\d{4})/,
|
||||
/^\-(\d{2})/,
|
||||
/^\-(\d{2})/,
|
||||
/^(?:\s+|T|t)(\d{2})/,
|
||||
/^:(\d{2})/,
|
||||
/^:(\d{2})/
|
||||
],
|
||||
timeZoneOffset = [0, 0],
|
||||
timeData = [0, 0, 1, 0, 0, 0],
|
||||
bottomDate = null,
|
||||
topDate = null,
|
||||
const parseRes = [
|
||||
/^(\d{4})/,
|
||||
/^-(\d{2})/,
|
||||
/^-(\d{2})/,
|
||||
/^(?:\s+|T|t)(\d{2})/,
|
||||
/^:(\d{2})/,
|
||||
/^:(\d{2})/
|
||||
],
|
||||
timeZoneOffset = [0, 0],
|
||||
timeData = [0, 0, 1, 0, 0, 0],
|
||||
origDateVal = dateVal;
|
||||
let topDate = null,
|
||||
i,
|
||||
match,
|
||||
origDateVal = dateVal;
|
||||
bottomDate = null,
|
||||
localDateVal = origDateVal;
|
||||
|
||||
match = /([\+\-])(\d{2}):(\d{2})$/.exec(dateVal);
|
||||
match = /([+-])(\d{2}):(\d{2})$/.exec(localDateVal);
|
||||
if (match) {
|
||||
timeZoneOffset[0] = parseInt(match[2], 10);
|
||||
timeZoneOffset[1] = parseInt(match[3], 10);
|
||||
|
@ -145,18 +146,18 @@ SearchTerm.prototype.parseAbsoluteDate = function(dateVal, qual) {
|
|||
timeZoneOffset[0] *= -1;
|
||||
timeZoneOffset[1] *= -1;
|
||||
}
|
||||
dateVal = dateVal.substr(0, dateVal.length - 6);
|
||||
localDateVal = localDateVal.substr(0, localDateVal.length - 6);
|
||||
}
|
||||
else {
|
||||
dateVal = dateVal.replace(/[Zz]$/, '');
|
||||
localDateVal = localDateVal.replace(/[Zz]$/, '');
|
||||
}
|
||||
|
||||
for (i = 0; i < parseRes.length; i += 1) {
|
||||
if (dateVal.length === 0) {
|
||||
if (localDateVal.length === 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
match = parseRes[i].exec(dateVal);
|
||||
match = parseRes[i].exec(localDateVal);
|
||||
if (match) {
|
||||
if (i === 1) {
|
||||
timeData[i] = parseInt(match[1], 10) - 1;
|
||||
|
@ -164,17 +165,17 @@ SearchTerm.prototype.parseAbsoluteDate = function(dateVal, qual) {
|
|||
else {
|
||||
timeData[i] = parseInt(match[1], 10);
|
||||
}
|
||||
dateVal = dateVal.substr(
|
||||
match[0].length, dateVal.length - match[0].length
|
||||
localDateVal = localDateVal.substr(
|
||||
match[0].length, localDateVal.length - match[0].length
|
||||
);
|
||||
}
|
||||
else {
|
||||
throw `Cannot parse date string: ${origDateVal}`;
|
||||
throw new Error(`Cannot parse date string: ${origDateVal}`);
|
||||
}
|
||||
}
|
||||
|
||||
if (dateVal.length > 0) {
|
||||
throw `Cannot parse date string: ${origDateVal}`;
|
||||
if (localDateVal.length > 0) {
|
||||
throw new Error(`Cannot parse date string: ${origDateVal}`);
|
||||
}
|
||||
|
||||
// Apply the user-specified time zone offset. The JS Date constructor
|
||||
|
@ -210,9 +211,8 @@ SearchTerm.prototype.parseDate = function(dateVal, qual) {
|
|||
}
|
||||
};
|
||||
|
||||
SearchTerm.prototype.parse = function(substr) {
|
||||
let matchArr,
|
||||
rangeParsing,
|
||||
SearchTerm.prototype.parse = function() {
|
||||
let rangeParsing,
|
||||
candidateTermSpace,
|
||||
termCandidate;
|
||||
|
||||
|
@ -230,7 +230,7 @@ SearchTerm.prototype.parse = function(substr) {
|
|||
this.termSpace = 'tags';
|
||||
this.termType = 'literal';
|
||||
|
||||
matchArr = this.term.split(':');
|
||||
const matchArr = this.term.split(':');
|
||||
|
||||
if (matchArr.length > 1) {
|
||||
candidateTermSpace = matchArr[0];
|
||||
|
@ -258,7 +258,7 @@ SearchTerm.prototype.parse = function(substr) {
|
|||
this.term = termCandidate;
|
||||
this.termSpace = candidateTermSpace;
|
||||
}
|
||||
else if (candidateTermSpace == 'my') {
|
||||
else if (candidateTermSpace === 'my') {
|
||||
this.termType = 'my';
|
||||
this.termSpace = termCandidate;
|
||||
}
|
||||
|
@ -285,9 +285,9 @@ SearchTerm.prototype.parse = function(substr) {
|
|||
|
||||
SearchTerm.prototype._normalizeTerm = function() {
|
||||
if (!this.wildcardable) {
|
||||
return this.term.replace('\"', '"');
|
||||
return this.term.replace('"', '"');
|
||||
}
|
||||
return this.term.replace(/\\([^\*\?])/g, '$1');
|
||||
return this.term.replace(/\\([^*?])/g, '$1');
|
||||
};
|
||||
|
||||
SearchTerm.prototype.fuzzyMatch = function(targetStr) {
|
||||
|
@ -309,16 +309,16 @@ SearchTerm.prototype.fuzzyMatch = function(targetStr) {
|
|||
targetDistance = this.fuzz;
|
||||
}
|
||||
|
||||
targetStr = targetStr.toLowerCase();
|
||||
const targetStrLower = targetStr.toLowerCase();
|
||||
|
||||
for (i = 0; i <= targetStr.length; i += 1) {
|
||||
for (i = 0; i <= targetStrLower.length; i += 1) {
|
||||
v1.push(i);
|
||||
}
|
||||
|
||||
for (i = 0; i < this.term.length; i += 1) {
|
||||
v2[0] = i;
|
||||
for (j = 0; j < targetStr.length; j += 1) {
|
||||
const cost = this.term[i] === targetStr[j] ? 0 : 1;
|
||||
for (j = 0; j < targetStrLower.length; j += 1) {
|
||||
const cost = this.term[i] === targetStrLower[j] ? 0 : 1;
|
||||
v2[j + 1] = Math.min(
|
||||
// Deletion.
|
||||
v1[j + 1] + 1,
|
||||
|
@ -327,8 +327,8 @@ SearchTerm.prototype.fuzzyMatch = function(targetStr) {
|
|||
// Substitution or No Change.
|
||||
v1[j] + cost
|
||||
);
|
||||
if (i > 1 && j > 1 && this.term[i] === targetStr[j - 1] &&
|
||||
targetStr[i - 1] === targetStr[j]) {
|
||||
if (i > 1 && j > 1 && this.term[i] === targetStrLower[j - 1] &&
|
||||
targetStrLower[i - 1] === targetStrLower[j]) {
|
||||
v2[j + 1] = Math.min(v2[j], v0[j - 1] + cost);
|
||||
}
|
||||
}
|
||||
|
@ -339,7 +339,7 @@ SearchTerm.prototype.fuzzyMatch = function(targetStr) {
|
|||
v2 = temp;
|
||||
}
|
||||
|
||||
return v1[targetStr.length] <= targetDistance;
|
||||
return v1[targetStrLower.length] <= targetDistance;
|
||||
};
|
||||
|
||||
SearchTerm.prototype.exactMatch = function(targetStr) {
|
||||
|
@ -354,10 +354,8 @@ SearchTerm.prototype.interactionMatch = function(imageID, type, interaction, int
|
|||
let ret = false;
|
||||
|
||||
interactions.forEach(v => {
|
||||
if (v.image_id == imageID && v.interaction_type == type && (interaction == null || v.value == interaction)) {
|
||||
if (v.image_id === imageID && v.interaction_type === type && (interaction === null || v.value === interaction)) {
|
||||
ret = true;
|
||||
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -365,8 +363,9 @@ SearchTerm.prototype.interactionMatch = function(imageID, type, interaction, int
|
|||
};
|
||||
|
||||
SearchTerm.prototype.match = function(target) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-this-alias,consistent-this
|
||||
const ohffs = this;
|
||||
let ret = false,
|
||||
ohffs = this,
|
||||
compFunc,
|
||||
numbuh,
|
||||
date;
|
||||
|
@ -427,9 +426,9 @@ SearchTerm.prototype.match = function(target) {
|
|||
}
|
||||
else if (this.termType === 'date') {
|
||||
// Date matching.
|
||||
date = (new Date(
|
||||
date = new Date(
|
||||
target.getAttribute(termSpaceToImageField[this.termSpace])
|
||||
)).getTime();
|
||||
).getTime();
|
||||
|
||||
switch (this.compare) {
|
||||
// The open-left, closed-right date range specified by the
|
||||
|
@ -481,23 +480,25 @@ SearchTerm.prototype.match = function(target) {
|
|||
return ret;
|
||||
};
|
||||
|
||||
function generateLexArray(searchStr, options) {
|
||||
let opQueue = [],
|
||||
searchTerm = null,
|
||||
function generateLexArray(searchStr) {
|
||||
const opQueue = [],
|
||||
groupNegate = [],
|
||||
tokenStack = [];
|
||||
let searchTerm = null,
|
||||
boost = null,
|
||||
fuzz = null,
|
||||
lparenCtr = 0,
|
||||
negate = false,
|
||||
groupNegate = [],
|
||||
tokenStack = [],
|
||||
boostFuzzStr = '';
|
||||
boostFuzzStr = '',
|
||||
localSearchStr = searchStr;
|
||||
|
||||
while (searchStr.length > 0) {
|
||||
while (localSearchStr.length > 0) {
|
||||
// eslint-disable-next-line no-loop-func
|
||||
tokenList.every(tokenArr => {
|
||||
let tokenName = tokenArr[0],
|
||||
tokenRE = tokenArr[1],
|
||||
match = tokenRE.exec(searchStr),
|
||||
balanced, op;
|
||||
const tokenName = tokenArr[0],
|
||||
tokenRE = tokenArr[1];
|
||||
let match = tokenRE.exec(localSearchStr),
|
||||
op;
|
||||
|
||||
if (match) {
|
||||
match = match[0];
|
||||
|
@ -560,15 +561,18 @@ function generateLexArray(searchStr, options) {
|
|||
break;
|
||||
case 'rparen':
|
||||
if (lparenCtr > 0) {
|
||||
searchTerm.append(match);
|
||||
if (searchTerm) {
|
||||
searchTerm.append(match);
|
||||
}
|
||||
else {
|
||||
searchTerm = new SearchTerm(match);
|
||||
}
|
||||
lparenCtr -= 1;
|
||||
}
|
||||
else {
|
||||
balanced = false;
|
||||
while (opQueue.length) {
|
||||
op = opQueue.shift();
|
||||
if (op === 'lparen') {
|
||||
balanced = true;
|
||||
break;
|
||||
}
|
||||
tokenStack.push(op);
|
||||
|
@ -587,7 +591,7 @@ function generateLexArray(searchStr, options) {
|
|||
boostFuzzStr += match;
|
||||
}
|
||||
else {
|
||||
searchTerm = new SearchTerm(match, options);
|
||||
searchTerm = new SearchTerm(match);
|
||||
}
|
||||
break;
|
||||
case 'boost':
|
||||
|
@ -596,7 +600,7 @@ function generateLexArray(searchStr, options) {
|
|||
boostFuzzStr += match;
|
||||
}
|
||||
else {
|
||||
searchTerm = new SearchTerm(match, options);
|
||||
searchTerm = new SearchTerm(match);
|
||||
}
|
||||
break;
|
||||
case 'quoted_lit':
|
||||
|
@ -604,7 +608,7 @@ function generateLexArray(searchStr, options) {
|
|||
searchTerm.append(match);
|
||||
}
|
||||
else {
|
||||
searchTerm = new SearchTerm(match, options);
|
||||
searchTerm = new SearchTerm(match);
|
||||
}
|
||||
break;
|
||||
case 'word':
|
||||
|
@ -617,7 +621,7 @@ function generateLexArray(searchStr, options) {
|
|||
searchTerm.append(match);
|
||||
}
|
||||
else {
|
||||
searchTerm = new SearchTerm(match, options);
|
||||
searchTerm = new SearchTerm(match);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -628,8 +632,8 @@ function generateLexArray(searchStr, options) {
|
|||
}
|
||||
|
||||
// Truncate string and restart the token tests.
|
||||
searchStr = searchStr.substr(
|
||||
match.length, searchStr.length - match.length
|
||||
localSearchStr = localSearchStr.substr(
|
||||
match.length, localSearchStr.length - match.length
|
||||
);
|
||||
|
||||
// Break since we have found a match.
|
||||
|
@ -652,7 +656,7 @@ function generateLexArray(searchStr, options) {
|
|||
|
||||
if (opQueue.indexOf('rparen') !== -1 ||
|
||||
opQueue.indexOf('lparen') !== -1) {
|
||||
throw 'Mismatched parentheses.';
|
||||
throw new Error('Mismatched parentheses.');
|
||||
}
|
||||
|
||||
// Memory-efficient concatenation of remaining operators queue to the
|
||||
|
@ -663,8 +667,8 @@ function generateLexArray(searchStr, options) {
|
|||
}
|
||||
|
||||
function parseTokens(lexicalArray) {
|
||||
let operandStack = [],
|
||||
negate, op1, op2, parsed;
|
||||
const operandStack = [];
|
||||
let negate, op1, op2;
|
||||
lexicalArray.forEach((token, i) => {
|
||||
if (token !== 'not_op') {
|
||||
negate = lexicalArray[i + 1] === 'not_op';
|
||||
|
@ -674,7 +678,7 @@ function parseTokens(lexicalArray) {
|
|||
op1 = operandStack.pop();
|
||||
|
||||
if (typeof op1 === 'undefined' || typeof op2 === 'undefined') {
|
||||
throw 'Missing operand.';
|
||||
throw new Error('Missing operand.');
|
||||
}
|
||||
|
||||
operandStack.push(new SearchAST(token, negate, op1, op2));
|
||||
|
@ -691,7 +695,7 @@ function parseTokens(lexicalArray) {
|
|||
});
|
||||
|
||||
if (operandStack.length > 1) {
|
||||
throw 'Missing operator.';
|
||||
throw new Error('Missing operator.');
|
||||
}
|
||||
|
||||
op1 = operandStack.pop();
|
||||
|
@ -707,8 +711,8 @@ function parseTokens(lexicalArray) {
|
|||
return op1;
|
||||
}
|
||||
|
||||
function parseSearch(searchStr, options) {
|
||||
return parseTokens(generateLexArray(searchStr, options));
|
||||
function parseSearch(searchStr) {
|
||||
return parseTokens(generateLexArray(searchStr));
|
||||
}
|
||||
|
||||
function isTerminal(operand) {
|
||||
|
@ -724,25 +728,27 @@ function SearchAST(op, negate, leftOperand, rightOperand) {
|
|||
}
|
||||
|
||||
function combineOperands(ast1, ast2, parentAST) {
|
||||
let localAst1;
|
||||
if (parentAST.op === 'and_op') {
|
||||
ast1 = ast1 && ast2;
|
||||
localAst1 = ast1 && ast2;
|
||||
}
|
||||
else {
|
||||
ast1 = ast1 || ast2;
|
||||
localAst1 = ast1 || ast2;
|
||||
}
|
||||
|
||||
if (parentAST.negate) {
|
||||
return !ast1;
|
||||
return !localAst1;
|
||||
}
|
||||
|
||||
return ast1;
|
||||
return localAst1;
|
||||
}
|
||||
|
||||
// Evaluation of the AST in regard to a target image
|
||||
SearchAST.prototype.hitsImage = function(image) {
|
||||
let treeStack = [],
|
||||
// Left side node.
|
||||
ast1 = this,
|
||||
const treeStack = [];
|
||||
// Left side node.
|
||||
// eslint-disable-next-line @typescript-eslint/no-this-alias,consistent-this
|
||||
let ast1 = this,
|
||||
// Right side node.
|
||||
ast2,
|
||||
// Parent node of the current subtree.
|
||||
|
@ -834,9 +840,9 @@ SearchAST.prototype.hitsImage = function(image) {
|
|||
SearchAST.prototype.dumpTree = function() {
|
||||
// Dumps to string a simple diagram of the syntax tree structure
|
||||
// (starting with this object as the root) for debugging purposes.
|
||||
let retStrArr = [],
|
||||
treeQueue = [['', this]],
|
||||
treeArr,
|
||||
const retStrArr = [],
|
||||
treeQueue = [['', this]];
|
||||
let treeArr,
|
||||
prefix,
|
||||
tree;
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ import { delegate } from './utils/events';
|
|||
import store from './utils/store';
|
||||
|
||||
const NOTIFICATION_INTERVAL = 600000,
|
||||
NOTIFICATION_EXPIRES = 300000;
|
||||
NOTIFICATION_EXPIRES = 300000;
|
||||
|
||||
function makeRequest(verb) {
|
||||
return fetchJson(verb, '/notifications/unread').then(handleError);
|
||||
|
@ -17,7 +17,7 @@ function makeRequest(verb) {
|
|||
function bindSubscriptionLinks() {
|
||||
delegate(document, 'fetchcomplete', {
|
||||
'.js-subscription-link': event => {
|
||||
const target = $("#js-subscription-target");
|
||||
const target = $('#js-subscription-target');
|
||||
event.detail.text().then(text => {
|
||||
target.outerHTML = text;
|
||||
});
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { $, $$, clearEl, removeEl, insertBefore } from './utils/dom';
|
||||
import { $, $$, removeEl} from './utils/dom';
|
||||
import { delegate, leftClick } from './utils/events';
|
||||
|
||||
function pollOptionRemover(_event, target) {
|
||||
|
@ -28,7 +28,7 @@ function pollOptionCreator() {
|
|||
const newHtml = prevFieldCopy.outerHTML.replace(/(\d+)/g, `${existingOptionCount}`);
|
||||
|
||||
// Insert copy before the button
|
||||
addPollOptionButton.insertAdjacentHTML("beforebegin", newHtml);
|
||||
addPollOptionButton.insertAdjacentHTML('beforebegin', newHtml);
|
||||
existingOptionCount++;
|
||||
}
|
||||
|
||||
|
|
|
@ -90,11 +90,11 @@ function setupPreviews() {
|
|||
|
||||
const getCacheKey = () => {
|
||||
return (previewAnon && previewAnon.checked ? 'anon;' : '') + textarea.value;
|
||||
}
|
||||
};
|
||||
|
||||
const previewedTextAttribute = 'data-previewed-text';
|
||||
const updatePreview = () => {
|
||||
const cachedValue = getCacheKey()
|
||||
const cachedValue = getCacheKey();
|
||||
if (previewContent.getAttribute(previewedTextAttribute) === cachedValue) return;
|
||||
previewContent.setAttribute(previewedTextAttribute, cachedValue);
|
||||
|
||||
|
|
|
@ -41,8 +41,8 @@ const keyCodes = {
|
|||
82() { click('.js-rand'); }, // R - go to random image
|
||||
83() { click('.js-source-link'); }, // S - go to image source
|
||||
76() { click('.js-tag-sauce-toggle'); }, // L - edit tags
|
||||
79() { openFullView() }, // O - open original
|
||||
86() { openFullViewNewTab() }, // V - open original in a new tab
|
||||
79() { openFullView(); }, // O - open original
|
||||
86() { openFullViewNewTab(); }, // V - open original in a new tab
|
||||
70() { // F - favourite image
|
||||
getHover() ? click(`a.interaction--fave[data-image-id="${getHover()}"]`)
|
||||
: click('.block__header a.interaction--fave');
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
import { $$ } from './utils/dom';
|
||||
|
||||
function hideStaffTools() {
|
||||
if (window.booru.hideStaffTools == "true") {
|
||||
if (window.booru.hideStaffTools === 'true') {
|
||||
$$('.js-staff-action').forEach(el => {
|
||||
el.classList.add('hidden');
|
||||
});
|
||||
|
|
|
@ -102,7 +102,7 @@ function setupTagsInput(tagBlock) {
|
|||
if (name.length === 0 || tags.indexOf(name) !== -1) return;
|
||||
|
||||
// Remove instead if the tag name starts with a minus
|
||||
if (name[0] === "-") {
|
||||
if (name[0] === '-') {
|
||||
name = name.slice(1); // eslint-disable-line no-param-reassign
|
||||
const tagLink = $(`[data-tag-name="${escapeCss(name)}"]`, container);
|
||||
|
||||
|
|
|
@ -58,11 +58,11 @@ function formRemote(event, target) {
|
|||
headers: headers(),
|
||||
body: new FormData(target)
|
||||
}).then(response => {
|
||||
if (response && response.status == 300) {
|
||||
if (response && response.status === 300) {
|
||||
window.location.reload(true);
|
||||
return;
|
||||
}
|
||||
fire(target, 'fetchcomplete', response)
|
||||
fire(target, 'fetchcomplete', response);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -122,7 +122,7 @@ function setupImageUpload() {
|
|||
});
|
||||
|
||||
// Fetch on "enter" in url field
|
||||
remoteUrl.addEventListener("keydown", function(event) {
|
||||
remoteUrl.addEventListener('keydown', event => {
|
||||
if (event.keyCode === 13) { // Hit enter
|
||||
fetchButton.click();
|
||||
}
|
||||
|
|
1792
assets/package-lock.json
generated
1792
assets/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -1,21 +1,28 @@
|
|||
{
|
||||
"scripts": {
|
||||
"deploy": "cross-env NODE_ENV=production webpack",
|
||||
"lint": "eslint . --ext .js,.ts",
|
||||
"watch": "webpack --watch"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-free": "^5.15.4",
|
||||
"brunch": "^3.0.0",
|
||||
"copycat-brunch": "^1.1.1",
|
||||
"postcss": "^8.3.7"
|
||||
"postcss": "^8.3.7",
|
||||
"tslib": "^2.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-typescript": "^8.2.5",
|
||||
"@typescript-eslint/eslint-plugin": "^4.32.0",
|
||||
"@typescript-eslint/parser": "^4.32.0",
|
||||
"acorn": "^7.4.1",
|
||||
"autoprefixer": "^10.3.5",
|
||||
"copy-webpack-plugin": "^6.4.1",
|
||||
"cross-env": "^7.0.3",
|
||||
"css-loader": "^5.2.7",
|
||||
"css-minimizer-webpack-plugin": "^2.0.0",
|
||||
"eslint": "^7.32.0",
|
||||
"eslint-webpack-plugin": "^3.0.1",
|
||||
"file-loader": "^6.2.0",
|
||||
"ignore-emit-webpack-plugin": "^2.0.6",
|
||||
"mini-css-extract-plugin": "^2.3.0",
|
||||
|
@ -33,6 +40,7 @@
|
|||
"source-map-support": "^0.5.20",
|
||||
"style-loader": "^1.3.0",
|
||||
"terser-webpack-plugin": "^3.1.0",
|
||||
"typescript": "^4.4",
|
||||
"webpack": "^5.53.0",
|
||||
"webpack-cli": "^4.8.0",
|
||||
"webpack-rollup-loader": "^0.8.0"
|
||||
|
|
9
assets/tsconfig.json
Normal file
9
assets/tsconfig.json
Normal file
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"noEmit": true,
|
||||
"baseUrl": "./js",
|
||||
"target": "ES2018",
|
||||
"allowJs": true,
|
||||
"strict": true
|
||||
}
|
||||
}
|
|
@ -5,12 +5,14 @@ const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
|
|||
const CopyPlugin = require('copy-webpack-plugin');
|
||||
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
|
||||
const IgnoreEmitPlugin = require('ignore-emit-webpack-plugin');
|
||||
const ESLintPlugin = require('eslint-webpack-plugin');
|
||||
|
||||
const isDevelopment = process.env.NODE_ENV !== 'production';
|
||||
|
||||
const includePaths = require('rollup-plugin-includepaths')();
|
||||
const multiEntry = require('rollup-plugin-multi-entry')();
|
||||
const buble = require('rollup-plugin-buble')({ transforms: { dangerousForOf: true } });
|
||||
const typescript = require('@rollup/plugin-typescript')();
|
||||
|
||||
let plugins = [
|
||||
new IgnoreEmitPlugin(/css\/.*(?<!css)$/),
|
||||
|
@ -24,7 +26,16 @@ let plugins = [
|
|||
],
|
||||
}),
|
||||
];
|
||||
if (!isDevelopment){
|
||||
if (isDevelopment) {
|
||||
plugins = plugins.concat([
|
||||
new ESLintPlugin({
|
||||
extensions: ['js', 'ts'],
|
||||
failOnError: true,
|
||||
failOnWarning: isDevelopment
|
||||
})
|
||||
]);
|
||||
}
|
||||
else {
|
||||
plugins = plugins.concat([
|
||||
new TerserPlugin({
|
||||
cache: true,
|
||||
|
@ -90,6 +101,7 @@ module.exports = {
|
|||
buble,
|
||||
includePaths,
|
||||
multiEntry,
|
||||
typescript,
|
||||
]
|
||||
}
|
||||
},
|
||||
|
|
Loading…
Reference in a new issue