mirror of
https://gitlab.com/PronounsPage/PronounsPage.git
synced 2025-09-23 12:43:48 -04:00
Merge branch 'linting' into 'main'
Linting See merge request PronounsPage/PronounsPage!395
This commit is contained in:
commit
75653d45ce
55
.eslintrc.json
Normal file
55
.eslintrc.json
Normal file
@ -0,0 +1,55 @@
|
||||
{
|
||||
"env": {
|
||||
"es2021": true,
|
||||
"node": true
|
||||
},
|
||||
"root": true,
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:import/recommended",
|
||||
"plugin:vue/recommended"
|
||||
],
|
||||
"ignorePatterns": ["data", "dist", "new", "static", "census", "keys"],
|
||||
"parserOptions": {
|
||||
"ecmaVersion": "latest",
|
||||
"sourceType": "module"
|
||||
},
|
||||
"rules": {
|
||||
"curly": "warn",
|
||||
"eqeqeq": "warn",
|
||||
"no-constant-condition": "warn",
|
||||
"no-empty": "warn",
|
||||
"no-prototype-builtins": "warn",
|
||||
"no-template-curly-in-string": "error",
|
||||
"no-unused-vars": ["error", {"argsIgnorePattern": "^_", "varsIgnorePattern": "^_"}],
|
||||
"no-useless-escape": "warn",
|
||||
"no-useless-rename": "warn",
|
||||
"object-shorthand": "warn",
|
||||
"prefer-const": "warn",
|
||||
"prefer-template": "warn",
|
||||
"import/extensions": ["error", "always"],
|
||||
"import/no-cycle": "warn",
|
||||
"import/no-self-import": "error",
|
||||
"import/no-useless-path-segments": "error",
|
||||
"no-irregular-whitespace": "warn",
|
||||
"vue/html-closing-bracket-spacing": ["warn", {"selfClosingTag": "never"}],
|
||||
"vue/html-indent": ["warn", 4],
|
||||
"vue/html-self-closing": ["warn", {"html": {"void": "always", "normal": "never"}}],
|
||||
"vue/max-attributes-per-line": ["warn", {"singleline": 4}],
|
||||
"vue/multi-word-component-names": "off",
|
||||
"vue/no-mutating-props": "warn",
|
||||
"vue/no-use-v-if-with-v-for": ["warn"],
|
||||
"vue/require-v-for-key": "warn",
|
||||
"vue/script-indent": ["warn", 4],
|
||||
"vue/valid-template-root": "warn",
|
||||
"vue/valid-v-for": "warn"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["*.vue"],
|
||||
"rules": {
|
||||
"import/extensions": "off"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
@ -10,6 +10,11 @@ before_script:
|
||||
- make switch LANG=en
|
||||
- yarn install --immutable --immutable-cache --check-cache --cache-folder .yarn
|
||||
|
||||
lint:
|
||||
stage: test
|
||||
script:
|
||||
- yarn lint
|
||||
|
||||
unit-tests:
|
||||
stage: test
|
||||
script:
|
||||
|
3
Makefile
3
Makefile
@ -14,6 +14,9 @@ install:
|
||||
yarn
|
||||
node server/migrate.js
|
||||
|
||||
lint:
|
||||
yarn lint
|
||||
|
||||
test:
|
||||
yarn test
|
||||
|
||||
|
@ -209,7 +209,6 @@
|
||||
<script>
|
||||
import {socialProviders} from "../src/socialProviders";
|
||||
import {gravatar} from "../src/helpers";
|
||||
import cookieSettings from "../src/cookieSettings";
|
||||
import {mapState} from "vuex";
|
||||
import { usernameRegex } from '../src/username';
|
||||
|
||||
@ -351,7 +350,7 @@
|
||||
async deleteAccount() {
|
||||
await this.$confirm(this.$t('user.deleteAccountConfirm'), 'danger');
|
||||
|
||||
const response = await this.$post(`/user/delete`);
|
||||
await this.$post(`/user/delete`);
|
||||
|
||||
if (this.impersonationActive) {
|
||||
this.stopImpersonation();
|
||||
|
@ -186,12 +186,10 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ClientOnly from 'vue-client-only'
|
||||
import forbidden from "../src/forbidden";
|
||||
import {sleep} from "../src/helpers";
|
||||
|
||||
export default {
|
||||
components: { ClientOnly },
|
||||
props: {
|
||||
user: { required: true },
|
||||
profile: {},
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="calendar">
|
||||
<div v-for="i in (startingDayOfWeek - 1)"></div>
|
||||
<div v-for="i in (startingDayOfWeek - 1)" :key="i"></div>
|
||||
<component :is="tooltips || getDayClass(d) === 'day' ? 'div' : 'nuxt-link'"
|
||||
v-for="d in iterateMonth(year.year, month)" :key="d.toString()"
|
||||
:to="`/${config.calendar.route}/${d}`"
|
||||
|
@ -65,7 +65,7 @@
|
||||
}
|
||||
|
||||
let colourIndex = 0;
|
||||
new Chart(this.$el.getContext('2d'), {
|
||||
new window.Chart(this.$el.getContext('2d'), {
|
||||
type: this.type,
|
||||
data: {
|
||||
labels: this.isMultiDataset(this.data)
|
||||
|
@ -29,7 +29,6 @@
|
||||
<script>
|
||||
|
||||
// TODO remove duplication
|
||||
const escapeRegExp = s => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // https://stackoverflow.com/a/6969486/3297012
|
||||
const normalise = s => decodeURIComponent(s.trim().toLowerCase());
|
||||
const normaliseWithLink = s => normalise(s.replace(/^@/, '').replace(new RegExp('^https://.*?/@'), ''))
|
||||
|
||||
|
@ -20,7 +20,7 @@ export default {
|
||||
mounted() {
|
||||
if (!this.$refs.clipboard) { return; }
|
||||
const clipboard = new ClipboardJS(this.$refs.clipboard);
|
||||
clipboard.on('success', (e) => {
|
||||
clipboard.on('success', () => {
|
||||
this.clipboardFeedback = true;
|
||||
setTimeout(() => this.clipboardFeedback = false, 3000);
|
||||
});
|
||||
|
@ -105,7 +105,7 @@
|
||||
resolve(this.value);
|
||||
}
|
||||
},
|
||||
cancel(event) {
|
||||
cancel() {
|
||||
const reject = this.reject;
|
||||
this.hide();
|
||||
if (reject) {
|
||||
|
@ -156,7 +156,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Noun } from "~/src/classes";
|
||||
import { Noun } from '../src/classes';
|
||||
import { buildDict } from "../src/helpers";
|
||||
import hash from "../plugins/hash";
|
||||
|
||||
|
@ -20,7 +20,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { pronouns } from "~/src/data";
|
||||
import { pronouns } from '../src/data';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
|
@ -6,7 +6,7 @@
|
||||
</slot>
|
||||
</li>
|
||||
<li v-show="!allShown && hiddenCount > 0" :class="[itemClass, 'small']">
|
||||
<span v-if="static">
|
||||
<span v-if="isStatic">
|
||||
<Icon v="plus-circle"/>
|
||||
<T :params="{count: hiddenCount}">profile.expendableList.more</T>
|
||||
</span>
|
||||
@ -31,7 +31,7 @@ export default {
|
||||
values: { required: true },
|
||||
limit: { required: true },
|
||||
reducedLimit: { 'default': 4 },
|
||||
static: { type: Boolean },
|
||||
isStatic: { type: Boolean },
|
||||
expand: { type: Boolean },
|
||||
itemClass: {},
|
||||
},
|
||||
|
@ -193,7 +193,7 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
links: groupBy([...getContactLinks(this.config), ...getSocialLinks(this.config)], l => l.group),
|
||||
supportLinks: [...getSupportLinks(this.config)],
|
||||
supportLinks: [...getSupportLinks()],
|
||||
versionFrontend: process.env.VERSION,
|
||||
versionBackend: undefined,
|
||||
adsVisible: false,
|
||||
|
@ -176,7 +176,7 @@
|
||||
import { mapState } from 'vuex'
|
||||
import {DateTime} from "luxon";
|
||||
import forbidden from "../src/forbidden";
|
||||
import NounsNav from "../data/nouns/NounsNav";
|
||||
import NounsNav from '../data/nouns/NounsNav.vue';
|
||||
|
||||
export default {
|
||||
components: { NounsNav },
|
||||
|
@ -225,7 +225,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { InclusiveEntry } from "~/src/classes";
|
||||
import { InclusiveEntry } from '../src/classes';
|
||||
import { buildDict, clearUrl, clearLinkedText } from "../src/helpers";
|
||||
import hash from "../plugins/hash";
|
||||
|
||||
|
@ -112,7 +112,7 @@
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async submit(event) {
|
||||
async submit() {
|
||||
this.submitting = true;
|
||||
try {
|
||||
await this.$post(`/inclusive/submit`, this.form);
|
||||
|
@ -1,5 +1,5 @@
|
||||
<script>
|
||||
import Icon from './Icon';
|
||||
import Icon from './Icon.vue';
|
||||
import spelling from "../plugins/spelling";
|
||||
import { escapeHtml } from '../src/helpers';
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
if (this.escape) {
|
||||
text = escapeHtml(text);
|
||||
}
|
||||
if (!this.text) {
|
||||
if (!text) {
|
||||
return h('span');
|
||||
}
|
||||
|
||||
@ -71,7 +71,7 @@
|
||||
buffer = '';
|
||||
linkBuffer = '';
|
||||
}
|
||||
for (let c of this.text) {
|
||||
for (let c of text) {
|
||||
if (c === '{') {
|
||||
addChild();
|
||||
isLink = true;
|
||||
|
@ -81,7 +81,6 @@
|
||||
<script>
|
||||
import jwt from 'jsonwebtoken';
|
||||
import {socialProviders} from "../src/socialProviders";
|
||||
import cookieSettings from "../src/cookieSettings";
|
||||
|
||||
export default {
|
||||
data() {
|
||||
|
@ -8,7 +8,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {Day} from "@/src/calendar/helpers";
|
||||
import { Day } from '../src/calendar/helpers';
|
||||
import { calendar } from '../src/calendar/calendar';
|
||||
import { ImmutableArray } from '../src/helpers';
|
||||
|
||||
|
@ -34,7 +34,7 @@
|
||||
this.mode = this.getMode();
|
||||
this.isDark = this.detectDark();
|
||||
|
||||
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => this.isDark = this.detectDark());
|
||||
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => this.isDark = this.detectDark());
|
||||
|
||||
this.$eventHub.$on('mode-changed', mode => {
|
||||
if (mode !== this.mode) {
|
||||
|
@ -63,7 +63,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {clearUrl} from '~/src/helpers';
|
||||
import {clearUrl} from '../src/helpers';
|
||||
import LazyHydrate from 'vue-lazy-hydration';
|
||||
|
||||
export default {
|
||||
|
@ -154,7 +154,7 @@
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async submit(event) {
|
||||
async submit() {
|
||||
this.submitting = true;
|
||||
try {
|
||||
await this.$post(`/nouns/submit`, this.form);
|
||||
|
@ -34,13 +34,13 @@
|
||||
<T v-if="$te('profile.age')">profile.age</T><T v-else>profile.birthday</T><T>quotation.colon</T>
|
||||
{{ profile.age }}
|
||||
</p>
|
||||
<Timezone v-if="profile.timezone" :value="profile.timezone" :static="static"/>
|
||||
<Timezone v-if="profile.timezone" :value="profile.timezone" :isStatic="isStatic"/>
|
||||
</div>
|
||||
|
||||
<div v-if="profile.flags.length || profile.customFlags.length" :class="['col-12', manyFlagsLayout ? '' : 'col-lg-6']">
|
||||
<ClientOnly>
|
||||
<ExpandableList :values="[...profile.flags.filter(flag => allFlags[flag]), ...profile.customFlags]"
|
||||
:limit="32" :reducedLimit="8" class="list-inline" itemClass="list-inline-item p-1" :static="static" :expand="expandLinks">
|
||||
:limit="32" :reducedLimit="8" class="list-inline" itemClass="list-inline-item p-1" :isStatic="isStatic" :expand="expandLinks">
|
||||
<template v-slot="s">
|
||||
<Flag v-if="typeof(s.el) === 'string'"
|
||||
:termkey="allFlags[s.el]"
|
||||
@ -73,7 +73,7 @@
|
||||
<T>profile.names</T>
|
||||
</h3>
|
||||
|
||||
<ExpandableList :values="profile.names" :limit="16" class="list-unstyled" :static="static" :expand="expandLinks">
|
||||
<ExpandableList :values="profile.names" :limit="16" class="list-unstyled" :isStatic="isStatic" :expand="expandLinks">
|
||||
<template v-slot="s">
|
||||
<Opinion :word="convertName(s.el.value)" :opinion="s.el.opinion" :escape="false" :markdown="profile.markdown"
|
||||
:link="config.locale === 'tok' && config.pronouns.enabled ? `${config.pronouns.prefix}/${s.el.value}` : null"
|
||||
@ -87,7 +87,7 @@
|
||||
<T>profile.pronouns</T>
|
||||
</h3>
|
||||
|
||||
<ExpandableList :values="pronounOpinions" :limit="16" class="list-unstyled" :static="static" :expand="expandLinks">
|
||||
<ExpandableList :values="pronounOpinions" :limit="16" class="list-unstyled" :isStatic="isStatic" :expand="expandLinks">
|
||||
<template v-slot="s">
|
||||
<Opinion :word="typeof s.el.pronoun === 'string' ? s.el.pronoun : s.el.pronoun.name(glue)" :opinion="s.el.opinion" :link="`${config.pronouns.prefix || ''}/${s.el.link}`" :customOpinions="profile.opinions"/>
|
||||
</template>
|
||||
@ -99,9 +99,9 @@
|
||||
<T>profile.links</T>
|
||||
</h3>
|
||||
|
||||
<ExpandableList :values="profile.links" :limit="16" class="list-unstyled" :static="static" :expand="expandLinks">
|
||||
<ExpandableList :values="profile.links" :limit="16" class="list-unstyled" :isStatic="isStatic" :expand="expandLinks">
|
||||
<template v-slot="s">
|
||||
<ProfileLink :link="s.el" :expand="static" :verifiedLinks="profile.verifiedLinks || {}" :metadata="profile.linksMetadata[normaliseUrl(s.el)]"/>
|
||||
<ProfileLink :link="s.el" :expand="isStatic" :verifiedLinks="profile.verifiedLinks || {}" :metadata="profile.linksMetadata[normaliseUrl(s.el)]"/>
|
||||
</template>
|
||||
</ExpandableList>
|
||||
</div>
|
||||
@ -119,7 +119,7 @@
|
||||
<Spelling :text="column.header" :markdown="profile.markdown"/>
|
||||
</h4>
|
||||
|
||||
<ExpandableList :values="column.values" :limit="16" class="list-unstyled" :static="static" :expand="expandLinks">
|
||||
<ExpandableList :values="column.values" :limit="16" class="list-unstyled" :isStatic="isStatic" :expand="expandLinks">
|
||||
<template v-slot="s">
|
||||
<Opinion :word="s.el.value" :opinion="s.el.opinion" :customOpinions="profile.opinions" :markdown="profile.markdown"/>
|
||||
</template>
|
||||
@ -128,7 +128,7 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="clearfix" v-if="profile.events.length + profile.customEvents.length > 0 && !static">
|
||||
<section class="clearfix" v-if="profile.events.length + profile.customEvents.length > 0 && !isStatic">
|
||||
<h3>
|
||||
<Icon v="calendar"/>
|
||||
<T>profile.calendar.header</T>
|
||||
@ -137,7 +137,7 @@
|
||||
<PersonalCalendar :year="year" :events="[...profile.events, ...profile.customEvents]"/>
|
||||
</section>
|
||||
|
||||
<section class="clearfix" v-if="profile.circle.length > 0 && !static">
|
||||
<section class="clearfix" v-if="profile.circle.length > 0 && !isStatic">
|
||||
<h3>
|
||||
<Icon v="heart-circle"/>
|
||||
<T>profile.circles.header</T>
|
||||
@ -177,7 +177,7 @@
|
||||
user: { required: true },
|
||||
profile: { required: true },
|
||||
terms: { 'default': null },
|
||||
static: { type: Boolean },
|
||||
isStatic: { type: Boolean },
|
||||
expandLinks: { type: Boolean },
|
||||
},
|
||||
data() {
|
||||
|
@ -65,7 +65,7 @@
|
||||
|
||||
await this.$confirm(this.$t('admin.user.confirmRole', {username: this.user.username, role: roles}));
|
||||
|
||||
const response = await this.$post(`/user/${this.user.id}/set-roles`, { roles: roles});
|
||||
await this.$post(`/user/${this.user.id}/set-roles`, { roles: roles});
|
||||
|
||||
this.user.roles = roles;
|
||||
}
|
||||
|
@ -141,7 +141,7 @@
|
||||
this.page = 0;
|
||||
await this.loadData();
|
||||
},
|
||||
async query(after, before, t) {
|
||||
async query(after, before) {
|
||||
if (JSON.stringify(after) === JSON.stringify(before)) { return; }
|
||||
this.page = 0;
|
||||
await this.loadData();
|
||||
|
@ -15,7 +15,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {makeId} from "~/src/helpers";
|
||||
import { makeId } from '../src/helpers';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
|
@ -120,7 +120,7 @@
|
||||
|
||||
<script>
|
||||
import {pronounLibrary} from "../src/data";
|
||||
import {Source} from "@/src/classes";
|
||||
import { Source } from '../src/classes';
|
||||
|
||||
export default {
|
||||
data() {
|
||||
|
@ -30,7 +30,7 @@
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
links: [...getSupportLinks(this.config)],
|
||||
links: [...getSupportLinks()],
|
||||
}
|
||||
},
|
||||
}
|
||||
|
@ -111,7 +111,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { TermsEntry } from "~/src/classes";
|
||||
import { TermsEntry } from '../src/classes';
|
||||
import { buildDict, clearUrl, clearLinkedText } from "../src/helpers";
|
||||
import hash from "../plugins/hash";
|
||||
import { calendar } from '../src/calendar/calendar';
|
||||
|
@ -59,7 +59,7 @@
|
||||
<label class="text-nowrap"><strong>
|
||||
<T>profile.flags</T>
|
||||
</strong></label>
|
||||
<ListInput v-model="form.flags" v-slot="s"/>
|
||||
<ListInput v-model="form.flags"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-lg-4">
|
||||
@ -118,7 +118,7 @@
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async submit(event) {
|
||||
async submit() {
|
||||
this.submitting = true;
|
||||
try {
|
||||
await this.$post(`/terms/submit`, this.form);
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div v-if="timezone && dt">
|
||||
<p v-if="!static">
|
||||
<p v-if="!isStatic">
|
||||
<Icon v="clock"/>
|
||||
<T :params="{
|
||||
time: dt.toLocaleString(DateTime.TIME_SIMPLE),
|
||||
@ -32,7 +32,7 @@ export default {
|
||||
mixins: [ timezone ],
|
||||
props: {
|
||||
value: {},
|
||||
static: { type: Boolean },
|
||||
isStatic: { type: Boolean },
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
@ -49,7 +49,7 @@
|
||||
},
|
||||
async commitChanges() {
|
||||
await this.$confirm(`Do you want to commit ${this.changesCount} changes?`, 'success');
|
||||
const response = await this.$post(`/translations/propose`, {
|
||||
await this.$post(`/translations/propose`, {
|
||||
changes: this.translationChanges,
|
||||
});
|
||||
this.$store.commit('translationCommit');
|
||||
|
@ -5,7 +5,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import dark from "../plugins/dark";
|
||||
import dark from '../plugins/dark';
|
||||
|
||||
export default {
|
||||
mixins: [dark],
|
||||
|
@ -38,7 +38,7 @@
|
||||
import Vue from 'vue';
|
||||
import dark from "../plugins/dark";
|
||||
import sorter from "avris-sorter";
|
||||
import {sleep} from "../src/helpers";
|
||||
import { sleep } from "../src/helpers";
|
||||
import md5 from 'js-md5';
|
||||
|
||||
// no need to be super secure, just a sign that the page is not public
|
||||
@ -146,7 +146,7 @@
|
||||
await this.$loadScript('gtm', 'https://www.googletagmanager.com/gtag/js?id=G-TDJEP12Q3M');
|
||||
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
function gtag(){window.dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
gtag('config', 'G-TDJEP12Q3M');
|
||||
},
|
||||
|
@ -47,10 +47,8 @@
|
||||
|
||||
<script>
|
||||
import {NounDeclension} from "../../../src/classes";
|
||||
import NounsNav from "./NounsNav";
|
||||
|
||||
export default {
|
||||
components: { NounsNav },
|
||||
data() {
|
||||
return {
|
||||
declensions: {
|
||||
|
@ -175,9 +175,9 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {Noun, NounDeclension, SourceLibrary} from "../../../src/classes";
|
||||
import {head} from "../../../src/helpers";
|
||||
import NounsNav from "./NounsNav";
|
||||
import { Noun, NounDeclension, SourceLibrary } from '../../../src/classes.js';
|
||||
import { head } from '../../../src/helpers.js';
|
||||
import NounsNav from './NounsNav.vue';
|
||||
import templates from './dukatywy.tsv';
|
||||
|
||||
const dukajDeclension = new NounDeclension({
|
||||
|
@ -175,9 +175,9 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {Noun, NounDeclension, SourceLibrary} from "../../../src/classes";
|
||||
import {head} from "../../../src/helpers";
|
||||
import NounsNav from "./NounsNav";
|
||||
import { Noun, NounDeclension, SourceLibrary } from '../../../src/classes.js';
|
||||
import { head } from '../../../src/helpers.js';
|
||||
import NounsNav from './NounsNav.vue';
|
||||
import templates from './iksatywy.tsv';
|
||||
|
||||
const xDeclension = new NounDeclension({
|
||||
|
@ -82,10 +82,10 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {Noun, NounDeclension} from "../../../src/classes";
|
||||
import hash from "../../../plugins/hash";
|
||||
import {head} from "../../../src/helpers";
|
||||
import NounsNav from "./NounsNav";
|
||||
import { NounDeclension } from '../../../src/classes.js';
|
||||
import hash from '../../../plugins/hash.js';
|
||||
import { head } from '../../../src/helpers.js';
|
||||
import NounsNav from './NounsNav.vue';
|
||||
|
||||
export default {
|
||||
components: { NounsNav },
|
||||
|
@ -78,9 +78,9 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {Noun, SourceLibrary} from "../../../src/classes";
|
||||
import {head} from "../../../src/helpers";
|
||||
import NounsNav from "./NounsNav";
|
||||
import { Noun, SourceLibrary } from '../../../src/classes.js';
|
||||
import { head } from '../../../src/helpers.js';
|
||||
import NounsNav from './NounsNav.vue';
|
||||
|
||||
export default {
|
||||
components: { NounsNav },
|
||||
|
@ -215,7 +215,7 @@ export default {
|
||||
plugins: postCssPlugins,
|
||||
}
|
||||
},
|
||||
extend (config, ctx) {
|
||||
extend (config) {
|
||||
config.module.rules.push({
|
||||
test: /\.csv|\.tsv$/,
|
||||
loader: 'csv-loader',
|
||||
|
@ -9,6 +9,7 @@
|
||||
"start": "nuxt start",
|
||||
"export": "nuxt export",
|
||||
"serve": "nuxt serve",
|
||||
"lint": "eslint --ext .js,.vue .",
|
||||
"test": "node --experimental-vm-modules $(yarn bin jest)"
|
||||
},
|
||||
"dependencies": {
|
||||
@ -23,11 +24,9 @@
|
||||
"avris-generator": "^0.8.2",
|
||||
"avris-sorter": "^0.0.3",
|
||||
"aws-sdk": "^2.1425.0",
|
||||
"body-parser": "^1.20.2",
|
||||
"canvas": "^2.11.2",
|
||||
"cookie-parser": "^1.4.5",
|
||||
"cookie-universal-nuxt": "^2.1.4",
|
||||
"csurf": "^1.11.0",
|
||||
"dotenv": "^8.2.0",
|
||||
"express": "^4.17.1",
|
||||
"express-session": "^1.17.1",
|
||||
@ -92,6 +91,10 @@
|
||||
"clipboard": "^2.0.6",
|
||||
"css-loader": "^5.2.7",
|
||||
"csv-loader": "^3.0.3",
|
||||
"eslint": "^8.55.0",
|
||||
"eslint-plugin-import": "^2.29.0",
|
||||
"eslint-plugin-vue": "^9.19.2",
|
||||
"globals": "^13.24.0",
|
||||
"jest": "^29.7.0",
|
||||
"postcss": "^8.2.15",
|
||||
"postcss-import": "^13.0.0",
|
||||
|
@ -1,13 +1,13 @@
|
||||
<template>
|
||||
<Homepage v-if="config.header"/>
|
||||
<Select v-else/>
|
||||
<SelectVersion v-else/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Homepage from '../routes/homepage';
|
||||
import Select from '../routes/select';
|
||||
import Homepage from '../routes/homepage.vue';
|
||||
import SelectVersion from '../routes/select.vue';
|
||||
|
||||
export default {
|
||||
components: { Homepage, Select },
|
||||
components: { Homepage, SelectVersion },
|
||||
}
|
||||
</script>
|
||||
|
5
plugins/.eslintrc.json
Normal file
5
plugins/.eslintrc.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"env": {
|
||||
"browser": true
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
import Vue from 'vue'
|
||||
import VuejsDatePicker from 'vuejs-datepicker'
|
||||
|
||||
export default ({ app }) => {
|
||||
export default () => {
|
||||
Vue.component('datepicker', VuejsDatePicker);
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ export default ({ app, store }) => {
|
||||
|
||||
Vue.prototype.$loadScript = (name, src) => {
|
||||
if (!process.client || document.querySelectorAll(`script.${name}-script`).length > 0) {
|
||||
return new Promise((resolve, reject) => { resolve(); });
|
||||
return new Promise((resolve) => { resolve(); });
|
||||
}
|
||||
|
||||
let resolveFn; let rejectFn;
|
||||
@ -83,7 +83,7 @@ export default ({ app, store }) => {
|
||||
return decodeTime(ulid) / 1000;
|
||||
}
|
||||
|
||||
app.router.afterEach((to, from) => {
|
||||
app.router.afterEach(() => {
|
||||
if (typeof window !== 'undefined' && window.fusetag) {
|
||||
window.fusetag.pageInit();
|
||||
}
|
||||
|
@ -1,14 +1,9 @@
|
||||
function defaultHandler({plausible, to, from}) {
|
||||
function defaultHandler({plausible, to}) {
|
||||
console.debug("[analytics] Tracking default handler: %O", to);
|
||||
plausible.trackPageview({
|
||||
url: to.toString()
|
||||
})
|
||||
}
|
||||
function eventHandler(eventName) {
|
||||
return function ({plausible, to, from}) {
|
||||
plausible.trackEvent(eventName, {}, {});
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param {(value: URL) => URL} redactor
|
||||
* @param {(ctx) => void} base
|
||||
|
@ -43,7 +43,7 @@
|
||||
|
||||
<script>
|
||||
import {head} from "../src/helpers";
|
||||
import translator from "@/src/translator";
|
||||
import translator from '../src/translator';
|
||||
|
||||
export default {
|
||||
data() {
|
||||
|
@ -119,10 +119,8 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {deepSet, head} from "../src/helpers";
|
||||
import {head} from "../src/helpers";
|
||||
import {socialProviders} from "../src/socialProviders";
|
||||
import translator from '../src/translator';
|
||||
import Suml from 'suml';
|
||||
|
||||
export default {
|
||||
data() {
|
||||
@ -179,8 +177,8 @@ export default {
|
||||
const r = {};
|
||||
|
||||
Object.entries(this.stats)
|
||||
.filter(([locale, localeStats]) => locale !== '_' && locale !== 'calculatedAt')
|
||||
.sort(([aLocale, aLocaleStats], [bLocale, bLocaleStats]) => bLocaleStats.users - aLocaleStats.users)
|
||||
.filter(([locale, _localeStats]) => locale !== '_' && locale !== 'calculatedAt')
|
||||
.sort(([_aLocale, aLocaleStats], [_bLocale, bLocaleStats]) => bLocaleStats.users - aLocaleStats.users)
|
||||
.forEach(([locale, localeStats]) => {
|
||||
r[locale] = localeStats.users;
|
||||
});
|
||||
|
@ -64,7 +64,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { examples, pronouns, pronounLibrary } from "~/src/data";
|
||||
import { examples, pronouns, pronounLibrary } from '../src/data';
|
||||
import { head } from "../src/helpers";
|
||||
|
||||
export default {
|
||||
|
@ -191,7 +191,7 @@
|
||||
}),
|
||||
writins: buildDict(function* () {
|
||||
let i = 0;
|
||||
for (let question of questions) {
|
||||
for (let _question of questions) {
|
||||
yield [i, '']
|
||||
i++;
|
||||
}
|
||||
@ -199,7 +199,7 @@
|
||||
DateTime,
|
||||
}
|
||||
},
|
||||
async asyncData({ app, store }) {
|
||||
async asyncData({ app }) {
|
||||
const finished = await app.$axios.$get(`/census/finished`);
|
||||
const countResponses = await app.$axios.$get(`/census/count`);
|
||||
|
||||
|
@ -89,12 +89,6 @@
|
||||
<script>
|
||||
import {head} from "../src/helpers";
|
||||
|
||||
const rgbToHex = (rgb) => {
|
||||
if (!rgb.startsWith('rgb(')) { return rgb; }
|
||||
const [r, g, b] = rgb.replace(/^rgb\(/, '').replace(/\)$/, '').split(',')
|
||||
return `#${parseInt(r.trim()).toString(16)}${parseInt(g.trim()).toString(16)}${parseInt(b.trim()).toString(16)}`;
|
||||
}
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
|
@ -33,7 +33,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import EnglishTable from "../data/pronouns/EnglishTable";
|
||||
import EnglishTable from '../data/pronouns/EnglishTable.vue';
|
||||
import { head } from "../src/helpers";
|
||||
|
||||
export default {
|
||||
|
@ -21,10 +21,8 @@
|
||||
<script>
|
||||
import { head } from "../src/helpers";
|
||||
import hash from "../plugins/hash";
|
||||
import NounsNav from "../data/nouns/NounsNav.vue";
|
||||
|
||||
export default {
|
||||
components: { NounsNav },
|
||||
mixins: [ hash ],
|
||||
mounted() {
|
||||
this.handleHash(this.config.inclusive.hashNamespace || '', filter => {
|
||||
|
@ -115,7 +115,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {head, buildDict} from '~/src/helpers';
|
||||
import {head, buildDict} from '../src/helpers';
|
||||
import hash from "../plugins/hash";
|
||||
import {Name} from "../src/classes";
|
||||
|
||||
|
@ -40,7 +40,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { people } from "~/src/data";
|
||||
import { people } from '../src/data';
|
||||
import { head } from "../src/helpers";
|
||||
import {SourceLibrary} from "../src/classes";
|
||||
|
||||
|
@ -29,7 +29,7 @@
|
||||
<p><T>privacy.content.turnstile</T></p>
|
||||
<p v-if="config.ads && config.ads.enabled">
|
||||
<T>privacy.content.publift</T>
|
||||
<div data-fuse-privacy-tool></div>
|
||||
<span data-fuse-privacy-tool></span>
|
||||
<T>privacy.content.gtm</T>
|
||||
</p>
|
||||
<p><T>privacy.content.logsBackups</T></p>
|
||||
@ -41,7 +41,7 @@
|
||||
export default {
|
||||
methods: {
|
||||
revokeCookieConsent() {
|
||||
googlefc.callbackQueue.push(googlefc.showRevocationMessage);
|
||||
window.googlefc.callbackQueue.push(window.googlefc.showRevocationMessage);
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<Profile v-if="profile" :user="user" :profile="profile" class="pb-3 mt-5" static>
|
||||
<Profile v-if="profile" :user="user" :profile="profile" class="pb-3 mt-5" isStatic>
|
||||
<nuxt-link to="/">
|
||||
<h1 class="text-nowrap h5">
|
||||
<Logo style="font-size: 1.3em;"/>
|
||||
|
@ -313,7 +313,7 @@
|
||||
|
||||
<script>
|
||||
import {head, buildList, buildDict, isValidLink} from "../src/helpers";
|
||||
import { pronouns } from "~/src/data";
|
||||
import { pronouns } from '../src/data';
|
||||
import { buildPronoun } from "../src/buildPronoun";
|
||||
import config from '../data/config.suml';
|
||||
import link from '../plugins/link';
|
||||
|
@ -102,11 +102,11 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { examples, pronouns, getSources, pronounLibrary } from "~/src/data";
|
||||
import { examples, pronouns, pronounLibrary } from '../src/data';
|
||||
import {buildPronoun} from "../src/buildPronoun";
|
||||
import {head} from "../src/helpers";
|
||||
import GrammarTables from "../data/pronouns/GrammarTables";
|
||||
import LinkedText from "../components/LinkedText";
|
||||
import GrammarTables from '../data/pronouns/GrammarTables.vue';
|
||||
import LinkedText from '../components/LinkedText.vue';
|
||||
import {SourceLibrary} from "../src/classes";
|
||||
|
||||
export default {
|
||||
|
@ -235,12 +235,12 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { examples, pronouns, pronounLibrary } from "~/src/data";
|
||||
import { ExamplePart } from "~/src/classes";
|
||||
import { examples, pronouns, pronounLibrary } from '../src/data';
|
||||
import { ExamplePart } from '../src/classes';
|
||||
import Compressor from "../src/compressor";
|
||||
import MORPHEMES from '../data/pronouns/morphemes';
|
||||
import {mapState} from "vuex";
|
||||
import Suggested from "../data/pronouns/Suggested";
|
||||
import Suggested from '../data/pronouns/Suggested.vue';
|
||||
|
||||
export default {
|
||||
components: { Suggested },
|
||||
|
@ -23,11 +23,8 @@
|
||||
<script>
|
||||
import { head } from "../src/helpers";
|
||||
import hash from "../plugins/hash";
|
||||
import NounsNav from "../data/nouns/NounsNav.vue";
|
||||
|
||||
export default {
|
||||
components: { NounsNav },
|
||||
|
||||
mixins: [ hash ],
|
||||
mounted() {
|
||||
this.handleHash(this.config.terminology.hashNamespace || '', filter => {
|
||||
|
@ -18,7 +18,7 @@ const timer = ms => new Promise( res => setTimeout(res, ms));
|
||||
}
|
||||
const results = await Promise.all(chunk.map(({url}) => Promise.race([
|
||||
analyser.analyse(url),
|
||||
new Promise((resolve, reject) =>
|
||||
new Promise((resolve) =>
|
||||
setTimeout(() => resolve({url: url, error: new Error('timeout')}), 12000)
|
||||
),
|
||||
])));
|
||||
|
@ -11,7 +11,7 @@ const __dirname = new URL('.', import.meta.url).pathname;
|
||||
const locales = buildLocaleList('_');
|
||||
|
||||
const publishers = {
|
||||
async twitter(tweet, image, previousId, locale) {
|
||||
async twitter(tweet, _image, previousId, _locale) {
|
||||
const client = new Twitter({
|
||||
consumer_key: process.env.TWITTER_CALENDAR_CONSUMER_KEY,
|
||||
consumer_secret: process.env.TWITTER_CALENDAR_CONSUMER_SECRET,
|
||||
@ -73,8 +73,6 @@ const imageTmpPath = `${tmpDir}/calendar-tmp.png`;
|
||||
|
||||
const lastPostId = {};
|
||||
|
||||
const timer = ms => new Promise( res => setTimeout(res, ms));
|
||||
|
||||
(async () => {
|
||||
if (process.argv.length !== 4) {
|
||||
console.error('Missing parameters. Usage: node server/calendarBot.js <locales> <publishers>');
|
||||
@ -85,7 +83,7 @@ const timer = ms => new Promise( res => setTimeout(res, ms));
|
||||
console.log(locales[locale].name);
|
||||
|
||||
try {
|
||||
const { day, message, image } = await (await fetch(locales[locale].url + '/api/calendar/today')).json();
|
||||
const { message, image } = await (await fetch(locales[locale].url + '/api/calendar/today')).json();
|
||||
console.log('<<<', message, '>>>');
|
||||
if (!message) { continue; }
|
||||
|
||||
|
@ -79,7 +79,7 @@ const shoot = async (db, mode) => {
|
||||
continue;
|
||||
}
|
||||
|
||||
const s3putResponse = await s3.putObject({
|
||||
await s3.putObject({
|
||||
Key: key,
|
||||
Body: buffer,
|
||||
ContentType: 'image/png',
|
||||
|
@ -142,7 +142,7 @@ app.use(calendarRoute);
|
||||
app.use(translationsRoute);
|
||||
app.use(subscriptionRoute);
|
||||
|
||||
app.use(function (err, req, res, next) {
|
||||
app.use(function (err, req, res) {
|
||||
console.error(formatError(err, req));
|
||||
res.status(500).send('Unexpected server error');
|
||||
req.db.close();
|
||||
|
@ -53,7 +53,7 @@ const popularUnisex = {};
|
||||
const allFirstUnisex = {};
|
||||
const popularFirstUnisex = {};
|
||||
|
||||
_each(pesel, (counts, name) => {
|
||||
_each(pesel, (counts) => {
|
||||
counts['balanceBoth'] = calculateBalance(counts.K[0] + counts.K[1], counts.M[0] + counts.M[1]);
|
||||
counts['balanceFirst'] = calculateBalance(counts.K[0], counts.M[0]);
|
||||
counts['balanceBothPop'] = counts['balanceBoth'] * (counts.K[0] + counts.K[1] + counts.M[0] + counts.M[1]);
|
||||
|
@ -156,7 +156,7 @@ router.get('/admin/stats', handleErrorAsync(async (req, res) => {
|
||||
|
||||
const stats = await fetchStats(req);
|
||||
|
||||
for (let [locale, localeStats] of Object.entries(stats)) {
|
||||
for (let locale of Object.keys(stats)) {
|
||||
if (locale === '_' || locale === 'calculatedAt') { continue; }
|
||||
|
||||
if (!req.isGranted('panel', locale)) {
|
||||
|
@ -68,7 +68,7 @@ const buildMessage = (events, locale, day, link) => {
|
||||
const eventsSummary = (day, locale) => {
|
||||
const eventsRaw = calendar.getCurrentYear().eventsByDate[day.toString()];
|
||||
|
||||
const link = `${locale.url}/${encodeURIComponent(config.calendar.route)}/${day}`;
|
||||
const link = `${locale.url}/${encodeURIComponent(global.config.calendar.route)}/${day}`;
|
||||
const image = `${locale.url}/calendar/${day}.png`;
|
||||
|
||||
let message = null;
|
||||
|
@ -177,7 +177,7 @@ const calculateAggregate = (config, answer) => {
|
||||
case 'AND':
|
||||
return intersection(expected, answer).size === expected.size;
|
||||
default:
|
||||
throw new Exception(`Operation "${config.operation} not supported"`);
|
||||
throw new Error(`Operation "${config.operation} not supported"`);
|
||||
}
|
||||
}
|
||||
|
||||
@ -187,7 +187,7 @@ router.get('/census/export', handleErrorAsync(async (req, res) => {
|
||||
}
|
||||
|
||||
const report = [];
|
||||
for (let {answers, writins, troll} of await req.db.all(SQL`
|
||||
for (let {answers, writins} of await req.db.all(SQL`
|
||||
SELECT answers, writins FROM census
|
||||
WHERE locale = ${global.config.locale}
|
||||
AND edition = ${global.config.census.edition}
|
||||
@ -200,10 +200,10 @@ router.get('/census/export', handleErrorAsync(async (req, res) => {
|
||||
|
||||
const answer = {};
|
||||
let i = 0;
|
||||
for (let question of config.census.questions) {
|
||||
for (let question of global.config.census.questions) {
|
||||
if (question.type === 'checkbox') {
|
||||
const answerForAggregate = new Set();
|
||||
for (let [option, comment] of question.options) {
|
||||
for (let [option, _comment] of question.options) {
|
||||
const checked = (answers[i.toString()] || []).includes(option);
|
||||
answer[`${i}_${option}`] = checked ? 1 : '';
|
||||
if (checked) {
|
||||
@ -257,7 +257,7 @@ router.post('/census/moderation/decide', handleErrorAsync(async (req, res) => {
|
||||
return res.status(401).json({error: 'Unauthorised'});
|
||||
}
|
||||
|
||||
const queue = await req.db.get(SQL`
|
||||
await req.db.get(SQL`
|
||||
UPDATE census SET troll = ${parseInt(req.body.decision)} WHERE id = ${req.body.id}
|
||||
`);
|
||||
|
||||
|
@ -190,9 +190,9 @@ router.get('/nouns/:id.png', async (req, res) => {
|
||||
}
|
||||
|
||||
let maxItems = 0;
|
||||
['masc', 'fem', 'neutr'].forEach((form, column) => {
|
||||
['masc', 'fem', 'neutr'].forEach((form) => {
|
||||
let items = 0;
|
||||
for (let [key, symbol] of [['', '⋅'], ['Pl', '⁖']]) {
|
||||
for (let key of ['', 'Pl']) {
|
||||
items += noun[form + key].split('|').filter(x => x.length).length;
|
||||
}
|
||||
if (items > maxItems) {
|
||||
|
@ -21,7 +21,6 @@ import multer from "multer";
|
||||
|
||||
const __dirname = new URL('.', import.meta.url).pathname;
|
||||
|
||||
const escapeRegExp = s => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // https://stackoverflow.com/a/6969486/3297012
|
||||
const normalise = s => decodeURIComponent(s.trim().toLowerCase());
|
||||
const normaliseWithLink = s => normalise(s.replace(/^@/, '').replace(new RegExp('^https://.*?/@'), ''))
|
||||
|
||||
@ -349,8 +348,8 @@ const selectBestLocale = (availableLocales) => {
|
||||
return availableLocales[0];
|
||||
}
|
||||
|
||||
if (availableLocales.includes(config.locale)) {
|
||||
return config.locale;
|
||||
if (availableLocales.includes(global.config.locale)) {
|
||||
return global.config.locale;
|
||||
}
|
||||
|
||||
return '_';
|
||||
@ -976,13 +975,13 @@ router.post('/profile/import', multer({limits: {fileSize: 10 * 1024 * 1024}}).an
|
||||
return res.status(400).json({error: 'profile.backup.error.signature'});
|
||||
}
|
||||
|
||||
const {version, profiles, images} = JSON.parse(Buffer.from(payload, 'base64').toString('utf-8'));
|
||||
const {profiles, images} = JSON.parse(Buffer.from(payload, 'base64').toString('utf-8'));
|
||||
|
||||
const s3 = new S3(awsConfig);
|
||||
for (let [id, sizes] of Object.entries(images)) {
|
||||
for (let [size, content] of Object.entries(sizes)) {
|
||||
try {
|
||||
const data = await s3.headObject({
|
||||
await s3.headObject({
|
||||
Key: `images/${id}-${size}.png`,
|
||||
}).promise();
|
||||
continue;
|
||||
|
@ -59,7 +59,7 @@ router.get('/pronounce/:voice/:pronoun*', handleErrorAsync(async (req, res) => {
|
||||
Engine: voice.engine,
|
||||
}).promise();
|
||||
|
||||
const s3putResponse = await s3.putObject({
|
||||
await s3.putObject({
|
||||
Key: key,
|
||||
Body: pollyResponse.AudioStream,
|
||||
ContentType: pollyResponse.ContentType,
|
||||
|
@ -131,7 +131,6 @@ router.get('/translations/contributors', handleErrorAsync(async (req, res) => {
|
||||
`)) {
|
||||
const author_info = await req.db.get(SQL`SELECT username, roles FROM users WHERE id=${author_id}`);
|
||||
if (!author_info) { continue; }
|
||||
const { username, roles } = author_info;
|
||||
contributors.push({
|
||||
username: author_info.username,
|
||||
isMember: !!author_info.roles,
|
||||
|
@ -765,7 +765,6 @@ export class NounDeclension {
|
||||
|
||||
decline(word, plural) {
|
||||
const plurality = plural ? 'plural' : 'singular';
|
||||
const rep = Object.keys(this[plurality])[0];
|
||||
const base = word.substring(0, word.length - this.matches(word, plural));
|
||||
const options = this[plurality];
|
||||
|
||||
|
@ -176,6 +176,6 @@ export function* getSocialLinks(config) {
|
||||
yield* getLink(socialLinks, 'shop');
|
||||
}
|
||||
|
||||
export function* getSupportLinks(config) {
|
||||
export function* getSupportLinks() {
|
||||
yield* getLink(supportLinks, 'all');
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ export class LinkAnalyser {
|
||||
let $document;
|
||||
try {
|
||||
const controller = new AbortController();
|
||||
const timeout = setTimeout(() => controller.abort(), 10000);
|
||||
setTimeout(() => controller.abort(), 10000);
|
||||
const htmlString = await (await fetch(url, {signal: controller.signal})).text();
|
||||
$document = new JSDOM(htmlString, { virtualConsole: new VirtualConsole() });
|
||||
} catch (e) {
|
||||
@ -60,7 +60,7 @@ export class LinkAnalyser {
|
||||
try {
|
||||
const fallback = new URL('/favicon.ico', url);
|
||||
const controller = new AbortController();
|
||||
const timeout = setTimeout(() => controller.abort(), 1000);
|
||||
setTimeout(() => controller.abort(), 1000);
|
||||
const res = await fetch(fallback, {signal: controller.signal});
|
||||
if (res.ok) {
|
||||
return fallback;
|
||||
|
32
src/stats.js
32
src/stats.js
@ -7,38 +7,6 @@ import expectedTranslations from '../locale/expectedTranslations.js';
|
||||
import fs from 'fs';
|
||||
import Suml from 'suml';
|
||||
|
||||
// TODO all the duplication...
|
||||
const buildDict = (fn, ...args) => {
|
||||
const dict = {};
|
||||
for (let [key, value] of fn(...args)) {
|
||||
dict[key] = value;
|
||||
}
|
||||
return dict;
|
||||
}
|
||||
|
||||
const zip = (list, reverse) => {
|
||||
return buildDict(function* () {
|
||||
for (let [k, v] of list) {
|
||||
yield reverse ? [v, k] : [k, v];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const sortByValue = (obj, reverse = false, firstN = -1) => {
|
||||
let list = [];
|
||||
for (let i in obj) {
|
||||
if (obj.hasOwnProperty(i)) {
|
||||
list.push([parseInt(obj[i]), i]);
|
||||
}
|
||||
}
|
||||
list = list.sort((a, b) => reverse ? b[0] - a[0] : a[0] - b[0]);
|
||||
if (firstN >= 0) {
|
||||
list = list.slice(0, firstN);
|
||||
}
|
||||
|
||||
return zip(list, true);
|
||||
}
|
||||
|
||||
const deepGet = (obj, path) => {
|
||||
let value = obj;
|
||||
for (let part of path.split('.')) {
|
||||
|
@ -76,7 +76,7 @@ export const mutations = {
|
||||
state.translationChanges = translationChanges;
|
||||
} else {
|
||||
state.translationChanges = buildDict(function* (that) {
|
||||
for (let k in that) {
|
||||
for (const k in that) {
|
||||
if (!that.hasOwnProperty(k)) { continue; }
|
||||
if (k !== key) {
|
||||
yield [k, that[k]];
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { jest } from '@jest/globals';
|
||||
import { beforeEach, describe, expect, jest, test } from '@jest/globals';
|
||||
|
||||
// workaround to be independent of the current selected locale
|
||||
jest.unstable_mockModule('../data/pronouns/morphemes.js', () => {
|
||||
|
Loading…
x
Reference in New Issue
Block a user