more towards parsing vps

This commit is contained in:
adueck 2023-08-09 16:04:36 +04:00
parent 3221bb1e89
commit 4893ef0d70
9 changed files with 860 additions and 117 deletions

View File

@ -20,6 +20,7 @@
"@types/react": "^17.0.3",
"@types/react-dom": "^17.0.2",
"bootstrap": "^4.6.0",
"jest-extended": "^4.0.1",
"node-fetch": "^3.2.10",
"node-fetch-commonjs": "^3.2.4",
"pbf": "^3.2.1",

View File

@ -31,10 +31,32 @@ export function lookup(s: Partial<T.DictionaryEntry>): T.DictionaryEntry[] {
return nounsAdjs.filter((e) => e[key] === value) as T.DictionaryEntry[];
}
export function verbLookup(
s: (e: T.VerbDictionaryEntry) => boolean
): T.VerbEntry[] {
return verbs.filter(({ entry }) => s(entry));
export function verbLookup(input: string): T.VerbEntry[] {
const s = input.slice(0, -1);
if (s.endsWith("ېږ")) {
return verbs.filter(
({ entry }) =>
entry.p.slice(0, -1) === s ||
entry.p === s.slice(0, -1) + "دل" ||
entry.p === s ||
entry.psp === s ||
entry.prp === s ||
entry.ssp === s
);
}
return verbs.filter(
({ entry }) =>
entry.p.slice(0, -1) === s ||
// for short intransitive forms
entry.p.slice(0, -3) === s ||
entry.p === s ||
entry.psp === s ||
entry.prp === s ||
entry.ssp === s ||
(entry.separationAtP &&
(entry.p.slice(entry.separationAtP) === s ||
entry.psp?.slice(entry.separationAtP) === s))
);
}
export function wordQuery(word: string, type: "adj"): T.AdjectiveEntry;

View File

@ -0,0 +1,413 @@
/* eslint-disable jest/valid-title */
import * as T from "../../../types";
import { verbLookup, wordQuery } from "./lookup";
import { parseVerb } from "./parse-verb";
import { tokenizer } from "./tokenizer";
const wahul = wordQuery("وهل", "verb");
const leekul = wordQuery("لیکل", "verb");
const manul = wordQuery("منل", "verb");
const rasedul = wordQuery("رسېدل", "verb");
const leedul = wordQuery("لیدل", "verb");
const khorul = wordQuery("خوړل", "verb");
const kenaastul = wordQuery("کېناستل", "verb");
const prexodul = wordQuery("پرېښودل", "verb");
const xodul = wordQuery("ښودل", "verb");
const kexodul = wordQuery("کېښودل", "verb");
const tests: {
label: string;
cases: {
input: string;
output: {
root?: {
persons: T.Person[];
aspects: T.Aspect[];
};
stem?: {
persons: T.Person[];
aspects: T.Aspect[];
};
verb: T.VerbEntry;
}[];
}[];
}[] = [
{
label: "with regular simple verbs",
cases: [
{
input: "وهلم",
output: [
{
root: {
persons: [T.Person.FirstSingMale, T.Person.FirstSingFemale],
aspects: ["imperfective", "perfective"],
},
verb: wahul,
},
],
},
{
input: "وهم",
output: [
{
root: {
persons: [T.Person.FirstSingMale, T.Person.FirstSingFemale],
aspects: ["imperfective", "perfective"],
},
stem: {
persons: [T.Person.FirstSingMale, T.Person.FirstSingFemale],
aspects: ["imperfective", "perfective"],
},
verb: wahul,
},
],
},
{
input: "وهې",
output: [
{
root: {
persons: [
T.Person.SecondSingMale,
T.Person.SecondSingFemale,
T.Person.ThirdPlurFemale,
],
aspects: ["imperfective", "perfective"],
},
stem: {
persons: [T.Person.SecondSingMale, T.Person.SecondSingFemale],
aspects: ["imperfective", "perfective"],
},
verb: wahul,
},
],
},
{
input: "لیکم",
output: [
{
root: {
persons: [T.Person.FirstSingMale, T.Person.FirstSingFemale],
aspects: ["imperfective", "perfective"],
},
stem: {
persons: [T.Person.FirstSingMale, T.Person.FirstSingFemale],
aspects: ["imperfective", "perfective"],
},
verb: leekul,
},
],
},
{
input: "لیکلو",
output: [
{
root: {
persons: [T.Person.FirstPlurMale, T.Person.FirstPlurFemale],
aspects: ["imperfective", "perfective"],
},
verb: leekul,
},
],
},
{
input: "لیکل",
output: [
{
root: {
persons: [T.Person.ThirdPlurMale],
aspects: ["imperfective", "perfective"],
},
verb: leekul,
},
],
},
{
input: "لیکلل",
output: [],
},
{
input: "منله",
output: [
{
root: {
persons: [T.Person.ThirdSingFemale],
aspects: ["imperfective", "perfective"],
},
verb: manul,
},
],
},
{
input: "مني",
output: [
{
stem: {
persons: [
T.Person.ThirdSingMale,
T.Person.ThirdSingFemale,
T.Person.ThirdPlurMale,
T.Person.ThirdPlurFemale,
],
aspects: ["imperfective", "perfective"],
},
verb: manul,
},
],
},
{
input: "منئ",
output: [
{
stem: {
persons: [T.Person.SecondPlurMale, T.Person.SecondPlurFemale],
aspects: ["imperfective", "perfective"],
},
root: {
persons: [T.Person.SecondPlurMale, T.Person.SecondPlurFemale],
aspects: ["imperfective", "perfective"],
},
verb: manul,
},
],
},
],
},
{
label: "with regular intransitive verbs",
cases: [
{
input: "رسېدلم",
output: [
{
root: {
persons: [T.Person.FirstSingMale, T.Person.FirstSingFemale],
aspects: ["imperfective", "perfective"],
},
verb: rasedul,
},
],
},
{
input: "رسېدم",
output: [
{
root: {
persons: [T.Person.FirstSingMale, T.Person.FirstSingFemale],
aspects: ["imperfective", "perfective"],
},
verb: rasedul,
},
],
},
{
input: "رسېږې",
output: [
{
stem: {
persons: [T.Person.SecondSingMale, T.Person.SecondSingFemale],
aspects: ["imperfective", "perfective"],
},
verb: rasedul,
},
],
},
// short version of intransitive as well
{
input: "رسئ",
output: [
{
stem: {
persons: [T.Person.SecondPlurMale, T.Person.SecondPlurFemale],
aspects: ["imperfective", "perfective"],
},
verb: rasedul,
},
],
},
],
},
{
label: "verbs with irregular stems",
cases: [
{
input: "وینم",
output: [
{
stem: {
persons: [T.Person.FirstSingMale, T.Person.FirstSingFemale],
aspects: ["imperfective", "perfective"],
},
verb: leedul,
},
],
},
{
input: "وینم",
output: [
{
stem: {
persons: [T.Person.FirstSingMale, T.Person.FirstSingFemale],
aspects: ["imperfective", "perfective"],
},
verb: leedul,
},
],
},
{
input: "لیده",
output: [
{
root: {
persons: [T.Person.ThirdSingFemale],
aspects: ["imperfective", "perfective"],
},
verb: leedul,
},
],
},
{
input: "خورې",
output: [
{
stem: {
persons: [T.Person.SecondSingMale, T.Person.SecondSingFemale],
aspects: ["imperfective", "perfective"],
},
verb: khorul,
},
],
},
{
input: "خوړي",
output: [],
},
{
input: "خوړم",
output: [
{
root: {
persons: [T.Person.FirstSingMale, T.Person.FirstSingFemale],
aspects: ["imperfective", "perfective"],
},
verb: khorul,
},
],
},
],
},
{
label: "verbs with seperating prefix",
cases: [
{
input: "کېني",
output: [
{
stem: {
persons: [
T.Person.ThirdSingMale,
T.Person.ThirdSingFemale,
T.Person.ThirdPlurMale,
T.Person.ThirdPlurFemale,
],
aspects: ["imperfective", "perfective"],
},
verb: kenaastul,
},
],
},
{
input: "نم",
output: [
{
stem: {
persons: [T.Person.FirstSingMale, T.Person.FirstSingFemale],
aspects: ["perfective"],
},
verb: kenaastul,
},
],
},
{
input: "پرېږدو",
output: [
{
stem: {
persons: [T.Person.FirstPlurMale, T.Person.FirstPlurFemale],
aspects: ["imperfective", "perfective"],
},
verb: prexodul,
},
],
},
{
input: "پرېښوده",
output: [
{
root: {
persons: [T.Person.ThirdSingFemale],
aspects: ["imperfective", "perfective"],
},
verb: prexodul,
},
],
},
{
input: "ښودله",
output: [
{
root: {
persons: [T.Person.ThirdSingFemale],
aspects: ["imperfective", "perfective"],
},
verb: xodul,
},
{
root: {
persons: [T.Person.ThirdSingFemale],
aspects: ["perfective"],
},
verb: prexodul,
},
{
root: {
persons: [T.Person.ThirdSingFemale],
aspects: ["perfective"],
},
verb: kexodul,
},
],
},
],
},
];
tests.forEach(({ label, cases }) => {
test(label, () => {
cases.forEach(({ input, output }) => {
const tokens = tokenizer(input);
const vbs = parseVerb(tokens, verbLookup).map((r) => r.body);
const madeVbsS = output.reduce<Omit<T.VBE, "ps">[]>((acc, o) => {
return [
...acc,
...(["root", "stem"] as const).flatMap((base) =>
(o[base]?.aspects || []).flatMap((aspect) =>
(o[base]?.persons || []).flatMap((person) => ({
type: "VB" as const,
person,
info: {
type: "verb" as const,
aspect,
base,
verb: o.verb,
},
}))
)
),
];
}, []);
expect(vbs).toIncludeSameMembers(madeVbsS);
});
});
});

View File

@ -2,63 +2,183 @@ import * as T from "../../../types";
export function parseVerb(
tokens: Readonly<T.Token[]>,
verbLookup: (s: (e: T.VerbDictionaryEntry) => boolean) => T.VerbEntry[]
verbLookup: (s: string) => T.VerbEntry[]
): T.ParseResult<Omit<T.VBE, "ps">>[] {
if (tokens.length === 0) {
return [];
}
const [first, ...rest] = tokens;
const people = getVerbEnding(first.s);
if (people.length === 0) {
return [];
}
const verbs = findByStem(first.s.slice(0, -1), verbLookup);
return people.flatMap((person) =>
verbs.map((verb) => ({
tokens: rest,
body: {
type: "VB",
person,
info: {
type: "verb",
aspect: "imperfective",
base: "stem",
verb,
},
},
errors: [],
}))
);
// TODO: can optimize this to not have to look for possible stems/roots if none
const verbs = verbLookup(first.s);
return matchVerbs(first.s, verbs, people).map((body) => ({
tokens: rest,
body,
errors: [],
}));
}
function getVerbEnding(p: string): T.Person[] {
function matchVerbs(
s: string,
entries: T.VerbEntry[],
people: {
root: T.Person[];
stem: T.Person[];
}
): Omit<T.VBE, "ps">[] {
const w: Omit<T.VBE, "ps">[] = [];
const base = s.endsWith("ل") ? s : s.slice(0, -1);
if (people.stem.length) {
const stemMatches = {
imperfective: entries.filter(({ entry: e }) => {
if (e.c.includes("comp")) {
return false;
}
if (e.psp) {
return e.psp === base;
}
if (e.c.includes("intrans.")) {
const miniRoot = e.p.slice(0, -3);
return miniRoot + "ېږ" === base || miniRoot === base;
} else {
return e.p.slice(0, -1) === base;
}
}),
perfective: entries.filter(({ entry: e }) => {
if (e.c.includes("comp")) {
return false;
}
if (e.ssp) {
const bSep = e.separationAtP ? e.ssp.slice(e.separationAtP) : "";
return bSep === base || e.ssp === base;
}
if (e.psp) {
const bSep = e.separationAtP ? e.psp.slice(e.separationAtP) : "";
return bSep === base || e.psp === base;
}
if (e.c.includes("intrans.")) {
const miniRoot = e.p.slice(0, -3);
return miniRoot + "ېږ" === base || miniRoot === base;
} else {
return e.p.slice(0, -1) === base;
}
}),
};
Object.entries(stemMatches).forEach(([aspect, entries]) => {
entries.forEach((verb) => {
people.stem.forEach((person) => {
w.push({
type: "VB",
person,
info: {
type: "verb",
aspect: aspect as T.Aspect,
base: "stem",
verb: verb,
},
});
});
});
});
}
if (people.root.length) {
const rootMatches = {
imperfective: entries.filter(
({ entry: e }) =>
!e.c.includes("comp") &&
(base === e.p || (!s.endsWith("ل") && base === e.p.slice(0, -1)))
),
perfective: entries.filter(({ entry: e }) => {
if (e.c.includes("comp")) {
return false;
}
if (e.separationAtP) {
const bSep = e.p.slice(e.separationAtP);
return (
base === bSep ||
base === e.p ||
(!s.endsWith("ل") &&
(base === e.p.slice(0, -1) || base === bSep.slice(0, -1)))
);
} else {
// TODO: perfective roots are so rare could optimize this with a couple of checks?
return e.prp
? e.prp === base || e.prp.slice(0, -1) === base
: base === e.p || (!s.endsWith("ل") && base === e.p.slice(0, -1));
}
}),
};
Object.entries(rootMatches).forEach(([aspect, entries]) => {
entries.forEach((verb) => {
people.root.forEach((person) => {
w.push({
type: "VB",
person,
info: {
type: "verb",
aspect: aspect as T.Aspect,
base: "root",
verb: verb,
},
});
});
});
});
}
return w;
}
function getVerbEnding(p: string): {
root: T.Person[];
stem: T.Person[];
} {
if (p.endsWith("م")) {
return [T.Person.FirstSingMale, T.Person.FirstSingFemale];
return {
root: [T.Person.FirstSingMale, T.Person.FirstSingFemale],
stem: [T.Person.FirstSingMale, T.Person.FirstSingFemale],
};
} else if (p.endsWith("ې")) {
return [T.Person.SecondSingMale, T.Person.SecondSingFemale];
return {
root: [
T.Person.SecondSingMale,
T.Person.SecondSingFemale,
T.Person.ThirdPlurFemale,
],
stem: [T.Person.SecondSingMale, T.Person.SecondSingFemale],
};
} else if (p.endsWith("ي")) {
return [
T.Person.ThirdSingMale,
T.Person.ThirdSingFemale,
T.Person.ThirdPlurMale,
T.Person.ThirdPlurFemale,
];
return {
stem: [
T.Person.ThirdSingMale,
T.Person.ThirdSingFemale,
T.Person.ThirdPlurMale,
T.Person.ThirdPlurFemale,
],
root: [],
};
} else if (p.endsWith("و")) {
return [T.Person.FirstPlurMale, T.Person.FirstPlurFemale];
return {
root: [T.Person.FirstPlurMale, T.Person.FirstPlurFemale],
stem: [T.Person.FirstPlurMale, T.Person.FirstPlurFemale],
};
} else if (p.endsWith("ئ")) {
return [T.Person.SecondPlurMale, T.Person.SecondPlurFemale];
return {
root: [T.Person.SecondPlurMale, T.Person.SecondPlurFemale],
stem: [T.Person.SecondPlurMale, T.Person.SecondPlurFemale],
};
} else if (p.endsWith("ه")) {
return {
root: [T.Person.ThirdSingFemale],
stem: [],
};
} else if (p.endsWith("ل")) {
return {
root: [T.Person.ThirdPlurMale],
stem: [],
};
}
return [];
}
function findByStem(
stem: string,
verbLookup: (s: (e: T.VerbDictionaryEntry) => boolean) => T.VerbEntry[]
): T.VerbEntry[] {
return verbLookup(
(e) =>
e.psp === stem ||
(!e.psp && !e.c.includes("comp") && e.p.slice(0, -1) === stem)
);
return {
root: [],
stem: [],
};
}

View File

@ -28,42 +28,167 @@ const kedulStat = vEntry({
ec: "become",
});
// cool examples: زه خوږې ماشومې وهم
export function parseVP(
tokens: Readonly<T.Token[]>,
lookup: (s: Partial<T.DictionaryEntry>) => T.DictionaryEntry[],
verbLookup: (s: (e: T.VerbDictionaryEntry) => boolean) => T.VerbEntry[]
verbLookup: (s: string) => T.VerbEntry[]
): T.ParseResult<T.VPSelectionComplete>[] {
if (tokens.length === 0) {
return [];
}
// how to make this into a nice pipeline... 🤔
const NP1 = parseNP(tokens, lookup).filter(({ errors }) => !errors.length);
const NP2 = bindParseResult(
NP1,
(tokens) => parseNP(tokens, lookup),
true
).filter(({ errors }) => !errors.length);
const vb = bindParseResult(
NP2,
(tokens) => parseVerb(tokens, verbLookup),
true
).filter(({ errors }) => !errors.length);
const NP2 = bindParseResult<
{
inflected: boolean;
selection: T.NPSelection;
},
{
np1: {
inflected: boolean;
selection: T.NPSelection;
};
np2:
| {
inflected: boolean;
selection: T.NPSelection;
}
| undefined;
}
>(NP1, (tokens, np1) => {
const np2s = parseNP(tokens, lookup);
if (!np2s.length) {
const r: T.ParseResult<{
np1: {
inflected: boolean;
selection: T.NPSelection;
};
np2: undefined;
}>[] = [
{
tokens,
body: {
np1,
np2: undefined,
},
errors: [],
},
];
return r;
}
return np2s.map((p) => ({
tokens: p.tokens,
body: {
np1,
np2: p.body,
},
errors: p.errors,
}));
}).filter(({ errors }) => !errors.length);
const vb = bindParseResult(NP2, (tokens, nps) => {
const vb = parseVerb(tokens, verbLookup);
// TODO make a nice functor that just maps or adds in the body
return vb.map((p) => ({
tokens: p.tokens,
body: {
np2: nps.np2,
v: p.body,
np1: nps.np1,
},
errors: p.errors,
}));
}).filter(({ errors }) => !errors.length);
// TODO: be able to bind mulitple vals
return bindParseResult<Omit<T.VBE, "ps">, T.VPSelectionComplete>(
vb,
(tokens, v) => {
const w: T.ParseResult<T.VPSelectionComplete>[] = [];
NP1.forEach(({ body: np1 }) => {
NP2.forEach(({ body: np2 }) => {
// NICE TODO: IF there's an error in any of the NPS, don't try
// to make the VPS - just show them that error
// for that we probably need a different type of
[
[np1, np2],
[np2, np1],
].forEach(([s, o]) => {
const errors: T.ParseError[] = [];
const subjPerson = getPersonFromNP(s.selection);
return bindParseResult(vb, (tokens, { np1, np2, v }) => {
const w: T.ParseResult<T.VPSelectionComplete>[] = [];
const isPast = v.info.type === "verb" && v.info.base === "root";
const intransitive =
v.info.type === "verb" && v.info.verb.entry.c.includes("intrans.");
if (!np2) {
const errors: T.ParseError[] = [];
const s = np1;
if (!intransitive) {
return [];
}
if (s.inflected) {
errors.push({
message: "subject of intransitive verb should not be inflected",
});
}
if (getPersonFromNP(s.selection) !== v.person) {
errors.push({
message: "subject should agree with intransitive verb",
});
}
const blocks: T.VPSBlockComplete[] = [
{
key: 1,
block: makeSubjectSelectionComplete(s.selection),
},
{
key: 2,
block: {
type: "objectSelection",
selection: "none",
},
},
];
const verb: T.VerbSelectionComplete = {
type: "verb",
verb: v.info.type === "verb" ? v.info.verb : kedulStat,
transitivity: "intransitive",
canChangeTransitivity: false,
canChangeStatDyn: false,
negative: false,
tense: isPast ? "imperfectivePast" : "presentVerb",
canChangeVoice: true,
isCompound: false,
voice: "active",
};
w.push({
tokens,
body: {
blocks,
verb,
externalComplement: undefined,
form: {
removeKing: false,
shrinkServant: false,
},
},
errors,
});
} else {
[[np1, np2, false] as const, [np2, np1, true] as const].forEach(
([s, o, reversed]) => {
const subjPerson = getPersonFromNP(s.selection);
const errors: T.ParseError[] = [];
if (intransitive) {
return [];
}
if (isPast) {
if (getPersonFromNP(o.selection) !== v.person) {
errors.push({
message: "transitive past tense verb does not match object",
});
} else {
if (!s.inflected) {
errors.push({
message: "transitive past tense subject should be inflected",
});
}
if (o.inflected) {
errors.push({
message:
"transitive past tense object should not be inflected",
});
}
}
} else {
if (getPersonFromNP(s.selection) !== v.person) {
errors.push({
message: "verb does not match subject",
@ -83,46 +208,49 @@ export function parseVP(
errors.push({ message: "object should not be inflected" });
}
}
}
const blocks: T.VPSBlockComplete[] = [
{
key: 1,
block: makeSubjectSelectionComplete(s.selection),
const blocks: T.VPSBlockComplete[] = [
{
key: 1,
block: makeSubjectSelectionComplete(s.selection),
},
{
key: 2,
block: makeObjectSelectionComplete(o.selection),
},
];
if (reversed) {
blocks.reverse();
}
const verb: T.VerbSelectionComplete = {
type: "verb",
verb: v.info.type === "verb" ? v.info.verb : kedulStat,
transitivity: "transitive",
canChangeTransitivity: false,
canChangeStatDyn: false,
negative: false,
tense: isPast ? "imperfectivePast" : "presentVerb",
canChangeVoice: true,
isCompound: false,
voice: "active",
};
w.push({
tokens,
body: {
blocks,
verb,
externalComplement: undefined,
form: {
removeKing: false,
shrinkServant: false,
},
{
key: 2,
block: makeObjectSelectionComplete(o.selection),
},
];
const verb: T.VerbSelectionComplete = {
type: "verb",
verb: v.info.type === "verb" ? v.info.verb : kedulStat,
transitivity: "transitive",
canChangeTransitivity: false,
canChangeStatDyn: false,
negative: false,
tense: "presentVerb",
canChangeVoice: true,
isCompound: false,
voice: "active",
};
w.push({
tokens,
body: {
blocks,
verb,
externalComplement: undefined,
form: {
removeKing: false,
shrinkServant: false,
},
},
errors,
});
},
errors,
});
});
});
return w;
}
);
}
);
return w;
});
}

View File

@ -2,4 +2,8 @@
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import '@testing-library/jest-dom';
import "@testing-library/jest-dom";
// add all jest-extended matchers
import * as matchers from "jest-extended";
expect.extend(matchers);

View File

@ -22,6 +22,7 @@
"jsx": "react-jsx"
},
"include": [
"src"
"src",
"testSetup.js"
]
}

View File

@ -1433,6 +1433,13 @@
optionalDependencies:
node-notifier "^8.0.0"
"@jest/schemas@^29.6.0":
version "29.6.0"
resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.0.tgz#0f4cb2c8e3dca80c135507ba5635a4fd755b0040"
integrity sha512-rxLjXyJBTL4LQeJW3aKo0M/+GkCOXsO+8i9Iu7eDb6KwtP65ayoDsitrdPBtujxQ88k4wI2FNYfa6TOGwSn6cQ==
dependencies:
"@sinclair/typebox" "^0.27.8"
"@jest/source-map@^26.6.2":
version "26.6.2"
resolved "https://registry.npmjs.org/@jest/source-map/-/source-map-26.6.2.tgz"
@ -1640,6 +1647,11 @@
estree-walker "^1.0.1"
picomatch "^2.2.2"
"@sinclair/typebox@^0.27.8":
version "0.27.8"
resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e"
integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==
"@sinonjs/commons@^1.7.0":
version "1.8.3"
resolved "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz"
@ -4283,6 +4295,11 @@ diff-sequences@^27.0.6:
resolved "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.0.6.tgz"
integrity sha512-ag6wfpBFyNXZ0p8pcuIDS//D8H062ZQJ3fzYxjpmeKjnz8W4pekL3AI8VohmyZmsWW2PWaHgjsmqR6L13101VQ==
diff-sequences@^29.4.3:
version "29.4.3"
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.4.3.tgz#9314bc1fabe09267ffeca9cbafc457d8499a13f2"
integrity sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==
diffie-hellman@^5.0.0:
version "5.0.3"
resolved "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz"
@ -6555,6 +6572,16 @@ jest-diff@^27.0.0:
jest-get-type "^27.0.6"
pretty-format "^27.2.4"
jest-diff@^29.0.0:
version "29.6.2"
resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.6.2.tgz#c36001e5543e82a0805051d3ceac32e6825c1c46"
integrity sha512-t+ST7CB9GX5F2xKwhwCf0TAR17uNDiaPTZnVymP9lw0lssa9vG+AFyDZoeIHStU3WowFFwT+ky+er0WVl2yGhA==
dependencies:
chalk "^4.0.0"
diff-sequences "^29.4.3"
jest-get-type "^29.4.3"
pretty-format "^29.6.2"
jest-docblock@^26.0.0:
version "26.0.0"
resolved "https://registry.npmjs.org/jest-docblock/-/jest-docblock-26.0.0.tgz"
@ -6598,6 +6625,14 @@ jest-environment-node@^26.6.2:
jest-mock "^26.6.2"
jest-util "^26.6.2"
jest-extended@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/jest-extended/-/jest-extended-4.0.1.tgz#2315cb5914fc132e5acd07945bfaa01aac3947c2"
integrity sha512-KM6dwuBUAgy6QONuR19CGubZB9Hkjqvl/d5Yc/FXsdB8+gsGxB2VQ+NEdOrr95J4GMPeLnDoPOKyi6+mKCCnZQ==
dependencies:
jest-diff "^29.0.0"
jest-get-type "^29.0.0"
jest-get-type@^26.3.0:
version "26.3.0"
resolved "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz"
@ -6608,6 +6643,11 @@ jest-get-type@^27.0.6:
resolved "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.0.6.tgz"
integrity sha512-XTkK5exIeUbbveehcSR8w0bhH+c0yloW/Wpl+9vZrjzztCPWrxhHwkIFpZzCt71oRBsgxmuUfxEqOYoZI2macg==
jest-get-type@^29.0.0, jest-get-type@^29.4.3:
version "29.4.3"
resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.4.3.tgz#1ab7a5207c995161100b5187159ca82dd48b3dd5"
integrity sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==
jest-haste-map@^26.6.2:
version "26.6.2"
resolved "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-26.6.2.tgz"
@ -9092,6 +9132,15 @@ pretty-format@^27.0.0, pretty-format@^27.2.4:
ansi-styles "^5.0.0"
react-is "^17.0.1"
pretty-format@^29.6.2:
version "29.6.2"
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.6.2.tgz#3d5829261a8a4d89d8b9769064b29c50ed486a47"
integrity sha512-1q0oC8eRveTg5nnBEWMXAU2qpv65Gnuf2eCQzSjxpWFkPaPARwqZZDGuNE0zPAZfTCHzIk3A8dIjwlQKKLphyg==
dependencies:
"@jest/schemas" "^29.6.0"
ansi-styles "^5.0.0"
react-is "^18.0.0"
process-nextick-args@~2.0.0:
version "2.0.1"
resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz"
@ -9396,6 +9445,11 @@ react-is@^17.0.1:
resolved "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz"
integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==
react-is@^18.0.0:
version "18.2.0"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b"
integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==
react-lifecycles-compat@^3.0.4:
version "3.0.4"
resolved "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz"