diff --git a/examples/simple/package-lock.json b/examples/simple/package-lock.json index 0068606ce..633bdc94f 100644 --- a/examples/simple/package-lock.json +++ b/examples/simple/package-lock.json @@ -9,7 +9,7 @@ "version": "0.0.1", "license": "ISC", "dependencies": { - "@snowtop/ent": "^0.1.0-alpha56", + "@snowtop/ent": "^0.1.0-alpha57", "@snowtop/ent-email": "^0.1.0-alpha1", "@snowtop/ent-passport": "^0.1.0-alpha1", "@snowtop/ent-password": "^0.1.0-alpha1", @@ -1019,9 +1019,9 @@ } }, "node_modules/@snowtop/ent": { - "version": "0.1.0-alpha56", - "resolved": "https://registry.npmjs.org/@snowtop/ent/-/ent-0.1.0-alpha56.tgz", - "integrity": "sha512-S9aMsEjbZQu+CeHETkSceKGTT1NbpD+1LIl4WXAKhCdckQEKpUAqd2C/xYhMkEhlkO/lufNKxLmNvKPBWFlUyw==", + "version": "0.1.0-alpha57", + "resolved": "https://registry.npmjs.org/@snowtop/ent/-/ent-0.1.0-alpha57.tgz", + "integrity": "sha512-TeH68Mlvy+YAFs78WZeDfRZ/ZA5vcWlWEcjhCSjMfIuD9Lpp3wceS2bFnto8cHFPv8sJDPJjDtGCKwt56z4qhA==", "dependencies": { "@types/node": "^15.0.2", "camel-case": "^4.1.2", @@ -8550,9 +8550,9 @@ } }, "@snowtop/ent": { - "version": "0.1.0-alpha56", - "resolved": "https://registry.npmjs.org/@snowtop/ent/-/ent-0.1.0-alpha56.tgz", - "integrity": "sha512-S9aMsEjbZQu+CeHETkSceKGTT1NbpD+1LIl4WXAKhCdckQEKpUAqd2C/xYhMkEhlkO/lufNKxLmNvKPBWFlUyw==", + "version": "0.1.0-alpha57", + "resolved": "https://registry.npmjs.org/@snowtop/ent/-/ent-0.1.0-alpha57.tgz", + "integrity": "sha512-TeH68Mlvy+YAFs78WZeDfRZ/ZA5vcWlWEcjhCSjMfIuD9Lpp3wceS2bFnto8cHFPv8sJDPJjDtGCKwt56z4qhA==", "requires": { "@types/node": "^15.0.2", "camel-case": "^4.1.2", diff --git a/examples/simple/package.json b/examples/simple/package.json index 0d72b1afe..d0e00f337 100644 --- a/examples/simple/package.json +++ b/examples/simple/package.json @@ -34,7 +34,7 @@ "tsconfig-paths": "^3.11.0" }, "dependencies": { - "@snowtop/ent": "^0.1.0-alpha56", + "@snowtop/ent": "^0.1.0-alpha57", "@snowtop/ent-email": "^0.1.0-alpha1", "@snowtop/ent-passport": "^0.1.0-alpha1", "@snowtop/ent-password": "^0.1.0-alpha1", diff --git a/examples/simple/src/ent/generated/const.ts b/examples/simple/src/ent/generated/const.ts index 99f189498..cda1cd2b6 100644 --- a/examples/simple/src/ent/generated/const.ts +++ b/examples/simple/src/ent/generated/const.ts @@ -41,6 +41,8 @@ export enum EdgeType { EventToInvited = "a72f5f64-3580-44fd-9bd0-d1335b803a46", // EventToMaybe is the edgeType for the event to maybe edge. EventToMaybe = "b0f6311b-fdab-4c26-b6bf-b751e0997735", + // GlobalToLoginAuth is the edgeType for the to loginauth edge. + GlobalToLoginAuth = "13eb6687-d226-4272-ba65-d5e33e00954c", // ObjectToComments is the edgeType for the object to comments edge. ObjectToComments = "8caba9c4-8035-447f-9eb1-4dd09a2d250c", // ObjectToLikers is the edgeType for the object to likers edge. diff --git a/examples/simple/src/schema/__global__schema.ts b/examples/simple/src/schema/__global__schema.ts new file mode 100644 index 000000000..53ad02d6e --- /dev/null +++ b/examples/simple/src/schema/__global__schema.ts @@ -0,0 +1,14 @@ +import { GlobalSchema } from "@snowtop/ent/schema/"; + +const glo: GlobalSchema = { + edges: [ + { + // TODO what's the best API to edit this to add/remove edges + // can add a new "Action" API just to get this + // Not Action or Builder though so just something that returns Changeset(s) + name: "loginAuth", + schemaName: "User", + }, + ], +}; +export default glo; diff --git a/examples/simple/src/schema/schema.py b/examples/simple/src/schema/schema.py index c9e076d40..e8d742542 100644 --- a/examples/simple/src/schema/schema.py +++ b/examples/simple/src/schema/schema.py @@ -145,6 +145,18 @@ sa.PrimaryKeyConstraint("id", name="events_id_pkey"), ) +sa.Table("global_login_auth_edges", metadata, + sa.Column("id1", postgresql.UUID(), nullable=False), + sa.Column("id1_type", sa.Text(), nullable=False), + sa.Column("edge_type", postgresql.UUID(), nullable=False), + sa.Column("id2", postgresql.UUID(), nullable=False), + sa.Column("id2_type", sa.Text(), nullable=False), + sa.Column("time", sa.TIMESTAMP(), nullable=False), + sa.Column("data", sa.Text(), nullable=True), + sa.PrimaryKeyConstraint("id1", "edge_type", "id2", name="global_login_auth_edges_id1_edge_type_id2_pkey"), + sa.Index("global_login_auth_edges_time_idx", "time"), +) + sa.Table("holidays", metadata, sa.Column("id", postgresql.UUID(), nullable=False), sa.Column("created_at", sa.TIMESTAMP(timezone=True), nullable=False), @@ -270,6 +282,7 @@ 'EventToHostsEdge': {"edge_name":"EventToHostsEdge", "edge_type":"ebe3e709-845c-4723-ac9c-29f983f2b8ea", "edge_table":"event_hosts_edges", "symmetric_edge":False, "inverse_edge_type":"cf6542a4-8bae-427f-8a1f-01194047afb3"}, 'EventToInvitedEdge': {"edge_name":"EventToInvitedEdge", "edge_type":"a72f5f64-3580-44fd-9bd0-d1335b803a46", "edge_table":"event_rsvps_edges", "symmetric_edge":False, "inverse_edge_type":"e439f2b2-d93a-4d1a-83f0-865bda5c8337"}, 'EventToMaybeEdge': {"edge_name":"EventToMaybeEdge", "edge_type":"b0f6311b-fdab-4c26-b6bf-b751e0997735", "edge_table":"event_rsvps_edges", "symmetric_edge":False, "inverse_edge_type":"8d5b1dee-ce65-452e-9f8d-78eca1993800"}, + 'GlobalToLoginAuthEdge': {"edge_name":"GlobalToLoginAuthEdge", "edge_type":"13eb6687-d226-4272-ba65-d5e33e00954c", "edge_table":"global_login_auth_edges", "symmetric_edge":False, "inverse_edge_type":None}, 'ObjectToCommentsEdge': {"edge_name":"ObjectToCommentsEdge", "edge_type":"8caba9c4-8035-447f-9eb1-4dd09a2d250c", "edge_table":"object_comments_edges", "symmetric_edge":False, "inverse_edge_type":"f430af94-d38a-4aaa-a92f-cfc56b6f811b"}, 'ObjectToLikersEdge': {"edge_name":"ObjectToLikersEdge", "edge_type":"c9ccdad9-7aff-40e4-9a69-2c29cfa19763", "edge_table":"object_likers_edges", "symmetric_edge":False, "inverse_edge_type":"745a20bf-4fdc-4862-b39f-569c4451db8f"}, 'UserToCreatedEventsEdge': {"edge_name":"UserToCreatedEventsEdge", "edge_type":"daa3b2a3-8245-40ca-ae77-25bfb82578a7", "edge_table":"user_created_events_edges", "symmetric_edge":False, "inverse_edge_type":None}, diff --git a/examples/simple/src/schema/schema.sql b/examples/simple/src/schema/schema.sql index 23069ac12..703034fba 100644 --- a/examples/simple/src/schema/schema.sql +++ b/examples/simple/src/schema/schema.sql @@ -114,6 +114,19 @@ CREATE TABLE events ( CONSTRAINT events_id_pkey PRIMARY KEY (id) ); +CREATE TABLE global_login_auth_edges ( + id1 UUID NOT NULL, + id1_type TEXT NOT NULL, + edge_type UUID NOT NULL, + id2 UUID NOT NULL, + id2_type TEXT NOT NULL, + time TIMESTAMP WITHOUT TIME ZONE NOT NULL, + data TEXT, + CONSTRAINT global_login_auth_edges_id1_edge_type_id2_pkey PRIMARY KEY (id1, edge_type, id2) +); + +CREATE INDEX global_login_auth_edges_time_idx ON global_login_auth_edges (time); + CREATE TABLE holidays ( id UUID NOT NULL, created_at TIMESTAMP WITH TIME ZONE NOT NULL, @@ -270,5 +283,5 @@ CREATE INDEX contacts_phone_number_ids_idx ON contacts USING gin (phone_number_i CREATE INDEX contacts_user_id_idx ON contacts (user_id); -INSERT INTO assoc_edge_config(edge_name, edge_type, edge_table, symmetric_edge, inverse_edge_type, created_at, updated_at) VALUES('AddressToHostedEventsEdge', 'd1979d4b-d033-4562-b078-cc528fec25bb', 'address_hosted_events_edges', false, NULL, now() AT TIME ZONE 'UTC', now() AT TIME ZONE 'UTC'), ('CommentToPostEdge', 'f430af94-d38a-4aaa-a92f-cfc56b6f811b', 'object_comments_edges', false, '8caba9c4-8035-447f-9eb1-4dd09a2d250c', now() AT TIME ZONE 'UTC', now() AT TIME ZONE 'UTC'), ('EventToAttendingEdge', '6ebc0c47-ea29-4635-b991-95e44162174d', 'event_rsvps_edges', false, '2a98ba02-e342-4bb4-93f6-5d7ed02f5c48', now() AT TIME ZONE 'UTC', now() AT TIME ZONE 'UTC'), ('EventToDeclinedEdge', 'db8d2454-f7b2-4147-aae1-e666daf3f3c3', 'event_rsvps_edges', false, '1c7c173b-63ce-4002-b121-4a87f82047dd', now() AT TIME ZONE 'UTC', now() AT TIME ZONE 'UTC'), ('EventToHostsEdge', 'ebe3e709-845c-4723-ac9c-29f983f2b8ea', 'event_hosts_edges', false, 'cf6542a4-8bae-427f-8a1f-01194047afb3', now() AT TIME ZONE 'UTC', now() AT TIME ZONE 'UTC'), ('EventToInvitedEdge', 'a72f5f64-3580-44fd-9bd0-d1335b803a46', 'event_rsvps_edges', false, 'e439f2b2-d93a-4d1a-83f0-865bda5c8337', now() AT TIME ZONE 'UTC', now() AT TIME ZONE 'UTC'), ('EventToMaybeEdge', 'b0f6311b-fdab-4c26-b6bf-b751e0997735', 'event_rsvps_edges', false, '8d5b1dee-ce65-452e-9f8d-78eca1993800', now() AT TIME ZONE 'UTC', now() AT TIME ZONE 'UTC'), ('ObjectToCommentsEdge', '8caba9c4-8035-447f-9eb1-4dd09a2d250c', 'object_comments_edges', false, 'f430af94-d38a-4aaa-a92f-cfc56b6f811b', now() AT TIME ZONE 'UTC', now() AT TIME ZONE 'UTC'), ('ObjectToLikersEdge', 'c9ccdad9-7aff-40e4-9a69-2c29cfa19763', 'object_likers_edges', false, '745a20bf-4fdc-4862-b39f-569c4451db8f', now() AT TIME ZONE 'UTC', now() AT TIME ZONE 'UTC'), ('UserToCreatedEventsEdge', 'daa3b2a3-8245-40ca-ae77-25bfb82578a7', 'user_created_events_edges', false, NULL, now() AT TIME ZONE 'UTC', now() AT TIME ZONE 'UTC'), ('UserToDeclinedEventsEdge', '1c7c173b-63ce-4002-b121-4a87f82047dd', 'event_rsvps_edges', false, 'db8d2454-f7b2-4147-aae1-e666daf3f3c3', now() AT TIME ZONE 'UTC', now() AT TIME ZONE 'UTC'), ('UserToEventsAttendingEdge', '2a98ba02-e342-4bb4-93f6-5d7ed02f5c48', 'event_rsvps_edges', false, '6ebc0c47-ea29-4635-b991-95e44162174d', now() AT TIME ZONE 'UTC', now() AT TIME ZONE 'UTC'), ('UserToFriendsEdge', 'd1a9316d-090f-4b02-b393-fd9372e2c905', 'user_friends_edges', true, NULL, now() AT TIME ZONE 'UTC', now() AT TIME ZONE 'UTC'), ('UserToHostedEventsEdge', 'cf6542a4-8bae-427f-8a1f-01194047afb3', 'event_hosts_edges', false, 'ebe3e709-845c-4723-ac9c-29f983f2b8ea', now() AT TIME ZONE 'UTC', now() AT TIME ZONE 'UTC'), ('UserToInvitedEventsEdge', 'e439f2b2-d93a-4d1a-83f0-865bda5c8337', 'event_rsvps_edges', false, 'a72f5f64-3580-44fd-9bd0-d1335b803a46', now() AT TIME ZONE 'UTC', now() AT TIME ZONE 'UTC'), ('UserToLikesEdge', '745a20bf-4fdc-4862-b39f-569c4451db8f', 'object_likers_edges', false, 'c9ccdad9-7aff-40e4-9a69-2c29cfa19763', now() AT TIME ZONE 'UTC', now() AT TIME ZONE 'UTC'), ('UserToMaybeEventsEdge', '8d5b1dee-ce65-452e-9f8d-78eca1993800', 'event_rsvps_edges', false, 'b0f6311b-fdab-4c26-b6bf-b751e0997735', now() AT TIME ZONE 'UTC', now() AT TIME ZONE 'UTC'), ('UserToPostEdge', '4b725578-e9f5-472c-8e57-e47481c9e1b8', 'object_comments_edges', false, '8caba9c4-8035-447f-9eb1-4dd09a2d250c', now() AT TIME ZONE 'UTC', now() AT TIME ZONE 'UTC'), ('UserToSelfContactEdge', 'd504201d-cf3f-4eef-b6a0-0b46a7ae186b', 'user_self_contact_edges', false, NULL, now() AT TIME ZONE 'UTC', now() AT TIME ZONE 'UTC'), ('UserToUserToHostedEventsEdge', 'e5555185-91bf-4322-8130-d0a00eb605b7', 'event_hosts_edges', false, 'ebe3e709-845c-4723-ac9c-29f983f2b8ea', now() AT TIME ZONE 'UTC', now() AT TIME ZONE 'UTC') ON CONFLICT DO NOTHING; +INSERT INTO assoc_edge_config(edge_name, edge_type, edge_table, symmetric_edge, inverse_edge_type, created_at, updated_at) VALUES('AddressToHostedEventsEdge', 'd1979d4b-d033-4562-b078-cc528fec25bb', 'address_hosted_events_edges', false, NULL, now() AT TIME ZONE 'UTC', now() AT TIME ZONE 'UTC'), ('CommentToPostEdge', 'f430af94-d38a-4aaa-a92f-cfc56b6f811b', 'object_comments_edges', false, '8caba9c4-8035-447f-9eb1-4dd09a2d250c', now() AT TIME ZONE 'UTC', now() AT TIME ZONE 'UTC'), ('EventToAttendingEdge', '6ebc0c47-ea29-4635-b991-95e44162174d', 'event_rsvps_edges', false, '2a98ba02-e342-4bb4-93f6-5d7ed02f5c48', now() AT TIME ZONE 'UTC', now() AT TIME ZONE 'UTC'), ('EventToDeclinedEdge', 'db8d2454-f7b2-4147-aae1-e666daf3f3c3', 'event_rsvps_edges', false, '1c7c173b-63ce-4002-b121-4a87f82047dd', now() AT TIME ZONE 'UTC', now() AT TIME ZONE 'UTC'), ('EventToHostsEdge', 'ebe3e709-845c-4723-ac9c-29f983f2b8ea', 'event_hosts_edges', false, 'cf6542a4-8bae-427f-8a1f-01194047afb3', now() AT TIME ZONE 'UTC', now() AT TIME ZONE 'UTC'), ('EventToInvitedEdge', 'a72f5f64-3580-44fd-9bd0-d1335b803a46', 'event_rsvps_edges', false, 'e439f2b2-d93a-4d1a-83f0-865bda5c8337', now() AT TIME ZONE 'UTC', now() AT TIME ZONE 'UTC'), ('EventToMaybeEdge', 'b0f6311b-fdab-4c26-b6bf-b751e0997735', 'event_rsvps_edges', false, '8d5b1dee-ce65-452e-9f8d-78eca1993800', now() AT TIME ZONE 'UTC', now() AT TIME ZONE 'UTC'), ('GlobalToLoginAuthEdge', '13eb6687-d226-4272-ba65-d5e33e00954c', 'global_login_auth_edges', false, NULL, now() AT TIME ZONE 'UTC', now() AT TIME ZONE 'UTC'), ('ObjectToCommentsEdge', '8caba9c4-8035-447f-9eb1-4dd09a2d250c', 'object_comments_edges', false, 'f430af94-d38a-4aaa-a92f-cfc56b6f811b', now() AT TIME ZONE 'UTC', now() AT TIME ZONE 'UTC'), ('ObjectToLikersEdge', 'c9ccdad9-7aff-40e4-9a69-2c29cfa19763', 'object_likers_edges', false, '745a20bf-4fdc-4862-b39f-569c4451db8f', now() AT TIME ZONE 'UTC', now() AT TIME ZONE 'UTC'), ('UserToCreatedEventsEdge', 'daa3b2a3-8245-40ca-ae77-25bfb82578a7', 'user_created_events_edges', false, NULL, now() AT TIME ZONE 'UTC', now() AT TIME ZONE 'UTC'), ('UserToDeclinedEventsEdge', '1c7c173b-63ce-4002-b121-4a87f82047dd', 'event_rsvps_edges', false, 'db8d2454-f7b2-4147-aae1-e666daf3f3c3', now() AT TIME ZONE 'UTC', now() AT TIME ZONE 'UTC'), ('UserToEventsAttendingEdge', '2a98ba02-e342-4bb4-93f6-5d7ed02f5c48', 'event_rsvps_edges', false, '6ebc0c47-ea29-4635-b991-95e44162174d', now() AT TIME ZONE 'UTC', now() AT TIME ZONE 'UTC'), ('UserToFriendsEdge', 'd1a9316d-090f-4b02-b393-fd9372e2c905', 'user_friends_edges', true, NULL, now() AT TIME ZONE 'UTC', now() AT TIME ZONE 'UTC'), ('UserToHostedEventsEdge', 'cf6542a4-8bae-427f-8a1f-01194047afb3', 'event_hosts_edges', false, 'ebe3e709-845c-4723-ac9c-29f983f2b8ea', now() AT TIME ZONE 'UTC', now() AT TIME ZONE 'UTC'), ('UserToInvitedEventsEdge', 'e439f2b2-d93a-4d1a-83f0-865bda5c8337', 'event_rsvps_edges', false, 'a72f5f64-3580-44fd-9bd0-d1335b803a46', now() AT TIME ZONE 'UTC', now() AT TIME ZONE 'UTC'), ('UserToLikesEdge', '745a20bf-4fdc-4862-b39f-569c4451db8f', 'object_likers_edges', false, 'c9ccdad9-7aff-40e4-9a69-2c29cfa19763', now() AT TIME ZONE 'UTC', now() AT TIME ZONE 'UTC'), ('UserToMaybeEventsEdge', '8d5b1dee-ce65-452e-9f8d-78eca1993800', 'event_rsvps_edges', false, 'b0f6311b-fdab-4c26-b6bf-b751e0997735', now() AT TIME ZONE 'UTC', now() AT TIME ZONE 'UTC'), ('UserToPostEdge', '4b725578-e9f5-472c-8e57-e47481c9e1b8', 'object_comments_edges', false, '8caba9c4-8035-447f-9eb1-4dd09a2d250c', now() AT TIME ZONE 'UTC', now() AT TIME ZONE 'UTC'), ('UserToSelfContactEdge', 'd504201d-cf3f-4eef-b6a0-0b46a7ae186b', 'user_self_contact_edges', false, NULL, now() AT TIME ZONE 'UTC', now() AT TIME ZONE 'UTC'), ('UserToUserToHostedEventsEdge', 'e5555185-91bf-4322-8130-d0a00eb605b7', 'event_hosts_edges', false, 'ebe3e709-845c-4723-ac9c-29f983f2b8ea', now() AT TIME ZONE 'UTC', now() AT TIME ZONE 'UTC') ON CONFLICT DO NOTHING; diff --git a/examples/simple/src/schema/versions/cca3dbdf4c48_20227286718_add_global_login_auth_edges_table_add_.py b/examples/simple/src/schema/versions/cca3dbdf4c48_20227286718_add_global_login_auth_edges_table_add_.py new file mode 100644 index 000000000..5ec488f52 --- /dev/null +++ b/examples/simple/src/schema/versions/cca3dbdf4c48_20227286718_add_global_login_auth_edges_table_add_.py @@ -0,0 +1,57 @@ +# Code generated by github.com/lolopinto/ent/ent, DO NOT edit. + +"""add global_login_auth_edges table +add index global_login_auth_edges_time_idx to global_login_auth_edges +add edge GlobalToLoginAuthEdge + +Revision ID: cca3dbdf4c48 +Revises: d1e063da4a0c +Create Date: 2022-07-28 06:07:18.688634+00:00 + +""" +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects import postgresql +from sqlalchemy.dialects import postgresql + +# revision identifiers, used by Alembic. +revision = 'cca3dbdf4c48' +down_revision = 'd1e063da4a0c' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('global_login_auth_edges', + sa.Column('id1', postgresql.UUID(), nullable=False), + sa.Column('id1_type', sa.Text(), nullable=False), + sa.Column('edge_type', postgresql.UUID(), nullable=False), + sa.Column('id2', postgresql.UUID(), nullable=False), + sa.Column('id2_type', sa.Text(), nullable=False), + sa.Column('time', sa.TIMESTAMP(), nullable=False), + sa.Column('data', sa.Text(), nullable=True), + sa.PrimaryKeyConstraint( + 'id1', 'edge_type', 'id2', name='global_login_auth_edges_id1_edge_type_id2_pkey') + ) + op.create_index('global_login_auth_edges_time_idx', + 'global_login_auth_edges', ['time'], unique=False) + op.add_edges([ + {'edge_name': 'GlobalToLoginAuthEdge', 'edge_type': '13eb6687-d226-4272-ba65-d5e33e00954c', + 'edge_table': 'global_login_auth_edges', 'symmetric_edge': False, 'inverse_edge_type': None}, + ]) + + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.remove_edges([ + {'edge_name': 'GlobalToLoginAuthEdge', 'edge_type': '13eb6687-d226-4272-ba65-d5e33e00954c', + 'edge_table': 'global_login_auth_edges', 'symmetric_edge': False, 'inverse_edge_type': None}, + ]) + + op.drop_index('global_login_auth_edges_time_idx', + table_name='global_login_auth_edges') + op.drop_table('global_login_auth_edges') + # ### end Alembic commands ### diff --git a/examples/todo-sqlite/ent.yml b/examples/todo-sqlite/ent.yml index 616d0bce8..23ae45ea9 100644 --- a/examples/todo-sqlite/ent.yml +++ b/examples/todo-sqlite/ent.yml @@ -1,7 +1,11 @@ +globalSchemaPath: global_schema.ts codegen: disableBase64Encoding: true generateRootResolvers: true defaultGraphQLMutationName: VerbNoun defaultGraphQLFieldFormat: snake_case fieldPrivacyEvaluated: at_ent_load + customAssocEdgePath: + path: 'src/ent/edge/custom_edge.ts' + name: 'CustomTodoEdge' diff --git a/examples/todo-sqlite/package-lock.json b/examples/todo-sqlite/package-lock.json index 160a1ffbb..118a22884 100644 --- a/examples/todo-sqlite/package-lock.json +++ b/examples/todo-sqlite/package-lock.json @@ -9,9 +9,9 @@ "version": "0.0.1", "license": "ISC", "dependencies": { - "@snowtop/ent": "^0.1.0-alpha51", + "@snowtop/ent": "^0.1.0-alpha55", "@snowtop/ent-phonenumber": "^0.1.0-alpha1", - "@snowtop/ent-soft-delete": "^0.1.0-alpha1", + "@snowtop/ent-soft-delete": "^0.1.0-alpha3", "@types/node": "^15.0.3", "@types/pg": "^8.6.1", "better-sqlite3": "^7.4.3", @@ -23,15 +23,15 @@ "devDependencies": { "@snowtop/ent-graphql-tests": "^0.1.0-alpha3", "@types/express": "^4.17.11", - "@types/jest": "^27.0.1", + "@types/jest": "^28.1.6", "@types/jest-expect-message": "^1.0.3", "@types/supertest": "^2.0.11", "@types/uuid": "^8.3.1", - "jest": "^27.4.3", + "jest": "^28.1.3", "jest-date-mock": "^1.0.8", "jest-expect-message": "^1.0.2", "supertest": "^6.1.3", - "ts-jest": "^27.1.0", + "ts-jest": "^28.0.7", "tsconfig-paths": "^3.11.0", "uuid": "^8.3.2" } @@ -260,9 +260,9 @@ } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz", - "integrity": "sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.9.tgz", + "integrity": "sha512-aBXPT3bmtLryXaoJLyYPXPlSD4p1ld9aYeR+sJNOZjJJGiOpb+fKfh3NkcCu7J54nUJwCERPBExCCpyCOHnu/w==", "dev": true, "engines": { "node": ">=6.9.0" @@ -584,12 +584,12 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.0.tgz", - "integrity": "sha512-Xv6mEXqVdaqCBfJFyeab0fH2DnUoMsDmhamxsSi4j8nLd4Vtw213WMJr55xxqipC/YVWyPY3K0blJncPYji+dQ==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.18.6.tgz", + "integrity": "sha512-mAWAuq4rvOepWCBid55JuRNvpTNf2UGVgoz4JV0fXEKolsVZDzsa4NqCef758WZJj/GDu0gVGItjKFiClTAmZA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -741,59 +741,60 @@ } }, "node_modules/@jest/console": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.4.2.tgz", - "integrity": "sha512-xknHThRsPB/To1FUbi6pCe43y58qFC03zfb6R7fDb/FfC7k2R3i1l+izRBJf8DI46KhYGRaF14Eo9A3qbBoixg==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-28.1.3.tgz", + "integrity": "sha512-QPAkP5EwKdK/bxIr6C1I4Vs0rm2nHiANzj/Z5X2JQkrZo6IqvC4ldZ9K95tF0HdidhA8Bo6egxSzUFPYKcEXLw==", "dev": true, "dependencies": { - "@jest/types": "^27.4.2", + "@jest/types": "^28.1.3", "@types/node": "*", "chalk": "^4.0.0", - "jest-message-util": "^27.4.2", - "jest-util": "^27.4.2", + "jest-message-util": "^28.1.3", + "jest-util": "^28.1.3", "slash": "^3.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/@jest/core": { - "version": "27.4.3", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.4.3.tgz", - "integrity": "sha512-V9ms3zSxUHxh1E/ZLAiXF7SLejsdFnjWTFizWotMOWvjho0lW5kSjZymhQSodNW0T0ZMQRiha7f8+NcFVm3hJQ==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-28.1.3.tgz", + "integrity": "sha512-CIKBrlaKOzA7YG19BEqCw3SLIsEwjZkeJzf5bdooVnW4bH5cktqe3JX+G2YV1aK5vP8N9na1IGWFzYaTp6k6NA==", "dev": true, "dependencies": { - "@jest/console": "^27.4.2", - "@jest/reporters": "^27.4.2", - "@jest/test-result": "^27.4.2", - "@jest/transform": "^27.4.2", - "@jest/types": "^27.4.2", + "@jest/console": "^28.1.3", + "@jest/reporters": "^28.1.3", + "@jest/test-result": "^28.1.3", + "@jest/transform": "^28.1.3", + "@jest/types": "^28.1.3", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", - "emittery": "^0.8.1", + "ci-info": "^3.2.0", "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "jest-changed-files": "^27.4.2", - "jest-config": "^27.4.3", - "jest-haste-map": "^27.4.2", - "jest-message-util": "^27.4.2", - "jest-regex-util": "^27.4.0", - "jest-resolve": "^27.4.2", - "jest-resolve-dependencies": "^27.4.2", - "jest-runner": "^27.4.3", - "jest-runtime": "^27.4.2", - "jest-snapshot": "^27.4.2", - "jest-util": "^27.4.2", - "jest-validate": "^27.4.2", - "jest-watcher": "^27.4.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^28.1.3", + "jest-config": "^28.1.3", + "jest-haste-map": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-regex-util": "^28.0.2", + "jest-resolve": "^28.1.3", + "jest-resolve-dependencies": "^28.1.3", + "jest-runner": "^28.1.3", + "jest-runtime": "^28.1.3", + "jest-snapshot": "^28.1.3", + "jest-util": "^28.1.3", + "jest-validate": "^28.1.3", + "jest-watcher": "^28.1.3", "micromatch": "^4.0.4", + "pretty-format": "^28.1.3", "rimraf": "^3.0.0", "slash": "^3.0.0", "strip-ansi": "^6.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" }, "peerDependencies": { "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" @@ -804,86 +805,222 @@ } } }, + "node_modules/@jest/core/node_modules/@jest/transform": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-28.1.3.tgz", + "integrity": "sha512-u5dT5di+oFI6hfcLOHGTAfmUxFRrjK+vnaP0kkVow9Md/M7V/MxqQMOz/VV25UZO8pzeA9PjfTpOu6BDuwSPQA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^28.1.3", + "@jridgewell/trace-mapping": "^0.3.13", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^28.1.3", + "jest-regex-util": "^28.0.2", + "jest-util": "^28.1.3", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/core/node_modules/jest-haste-map": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-28.1.3.tgz", + "integrity": "sha512-3S+RQWDXccXDKSWnkHa/dPwt+2qwA8CJzR61w3FoYCvoo3Pn8tvGcysmMF0Bj0EX5RYvAI2EIvC57OmotfdtKA==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^28.0.2", + "jest-util": "^28.1.3", + "jest-worker": "^28.1.3", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/@jest/core/node_modules/jest-regex-util": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", + "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/core/node_modules/jest-worker": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.3.tgz", + "integrity": "sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/core/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/@jest/core/node_modules/write-file-atomic": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.1.tgz", + "integrity": "sha512-nSKUxgAbyioruk6hU87QzVbY279oYT6uiwgDoujth2ju4mJ+TZau7SQBhtbTmUyuNYTuXnSyRn66FV0+eCgcrQ==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" + } + }, "node_modules/@jest/environment": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.4.2.tgz", - "integrity": "sha512-uSljKxh/rGlHlmhyeG4ZoVK9hOec+EPBkwTHkHKQ2EqDu5K+MaG9uJZ8o1CbRsSdZqSuhXvJCYhBWsORPPg6qw==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-28.1.3.tgz", + "integrity": "sha512-1bf40cMFTEkKyEf585R9Iz1WayDjHoHqvts0XFYEqyKM3cFWDpeMoqKKTAF9LSYQModPUlh8FKptoM2YcMWAXA==", "dev": true, "dependencies": { - "@jest/fake-timers": "^27.4.2", - "@jest/types": "^27.4.2", + "@jest/fake-timers": "^28.1.3", + "@jest/types": "^28.1.3", "@types/node": "*", - "jest-mock": "^27.4.2" + "jest-mock": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-28.1.3.tgz", + "integrity": "sha512-lzc8CpUbSoE4dqT0U+g1qODQjBRHPpCPXissXD4mS9+sWQdmmpeJ9zSH1rS1HEkrsMN0fb7nKrJ9giAR1d3wBw==", + "dev": true, + "dependencies": { + "expect": "^28.1.3", + "jest-snapshot": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-28.1.3.tgz", + "integrity": "sha512-wvbi9LUrHJLn3NlDW6wF2hvIMtd4JUl2QNVrjq+IBSHirgfrR3o9RnVtxzdEGO2n9JyIWwHnLfby5KzqBGg2YA==", + "dev": true, + "dependencies": { + "jest-get-type": "^28.0.2" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/expect-utils/node_modules/jest-get-type": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", + "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/@jest/fake-timers": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.4.2.tgz", - "integrity": "sha512-f/Xpzn5YQk5adtqBgvw1V6bF8Nx3hY0OIRRpCvWcfPl0EAjdqWPdhH3t/3XpiWZqtjIEHDyMKP9ajpva1l4Zmg==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-28.1.3.tgz", + "integrity": "sha512-D/wOkL2POHv52h+ok5Oj/1gOG9HSywdoPtFsRCUmlCILXNn5eIWmcnd3DIiWlJnpGvQtmajqBP95Ei0EimxfLw==", "dev": true, "dependencies": { - "@jest/types": "^27.4.2", - "@sinonjs/fake-timers": "^8.0.1", + "@jest/types": "^28.1.3", + "@sinonjs/fake-timers": "^9.1.2", "@types/node": "*", - "jest-message-util": "^27.4.2", - "jest-mock": "^27.4.2", - "jest-util": "^27.4.2" + "jest-message-util": "^28.1.3", + "jest-mock": "^28.1.3", + "jest-util": "^28.1.3" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/@jest/globals": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.4.2.tgz", - "integrity": "sha512-KkfaHEttlGpXYAQTZHgrESiEPx2q/DKAFLGLFda1uGVrqc17snd3YVPhOxlXOHIzVPs+lQ/SDB2EIvxyGzb3Ew==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-28.1.3.tgz", + "integrity": "sha512-XFU4P4phyryCXu1pbcqMO0GSQcYe1IsalYCDzRNyhetyeyxMcIxa11qPNDpVNLeretItNqEmYYQn1UYz/5x1NA==", "dev": true, "dependencies": { - "@jest/environment": "^27.4.2", - "@jest/types": "^27.4.2", - "expect": "^27.4.2" + "@jest/environment": "^28.1.3", + "@jest/expect": "^28.1.3", + "@jest/types": "^28.1.3" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/@jest/reporters": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.4.2.tgz", - "integrity": "sha512-sp4aqmdBJtjKetEakzDPcZggPcVIF6w9QLkYBbaWDV6e/SIsHnF1S4KtIH91eEc2fp7ep6V/e1xvdfEoho1d2w==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-28.1.3.tgz", + "integrity": "sha512-JuAy7wkxQZVNU/V6g9xKzCGC5LVXx9FDcABKsSXp5MiKPEE2144a/vXTEDoyzjUpZKfVwp08Wqg5A4WfTMAzjg==", "dev": true, "dependencies": { "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^27.4.2", - "@jest/test-result": "^27.4.2", - "@jest/transform": "^27.4.2", - "@jest/types": "^27.4.2", + "@jest/console": "^28.1.3", + "@jest/test-result": "^28.1.3", + "@jest/transform": "^28.1.3", + "@jest/types": "^28.1.3", + "@jridgewell/trace-mapping": "^0.3.13", "@types/node": "*", "chalk": "^4.0.0", "collect-v8-coverage": "^1.0.0", "exit": "^0.1.2", - "glob": "^7.1.2", - "graceful-fs": "^4.2.4", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^4.0.3", + "istanbul-lib-instrument": "^5.1.0", "istanbul-lib-report": "^3.0.0", "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.0.2", - "jest-haste-map": "^27.4.2", - "jest-resolve": "^27.4.2", - "jest-util": "^27.4.2", - "jest-worker": "^27.4.2", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^28.1.3", + "jest-util": "^28.1.3", + "jest-worker": "^28.1.3", "slash": "^3.0.0", - "source-map": "^0.6.0", "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", "terminal-link": "^2.0.0", - "v8-to-istanbul": "^8.1.0" + "v8-to-istanbul": "^9.0.1" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" }, "peerDependencies": { "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" @@ -894,92 +1031,275 @@ } } }, + "node_modules/@jest/reporters/node_modules/@jest/transform": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-28.1.3.tgz", + "integrity": "sha512-u5dT5di+oFI6hfcLOHGTAfmUxFRrjK+vnaP0kkVow9Md/M7V/MxqQMOz/VV25UZO8pzeA9PjfTpOu6BDuwSPQA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^28.1.3", + "@jridgewell/trace-mapping": "^0.3.13", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^28.1.3", + "jest-regex-util": "^28.0.2", + "jest-util": "^28.1.3", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/reporters/node_modules/jest-haste-map": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-28.1.3.tgz", + "integrity": "sha512-3S+RQWDXccXDKSWnkHa/dPwt+2qwA8CJzR61w3FoYCvoo3Pn8tvGcysmMF0Bj0EX5RYvAI2EIvC57OmotfdtKA==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^28.0.2", + "jest-util": "^28.1.3", + "jest-worker": "^28.1.3", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/@jest/reporters/node_modules/jest-regex-util": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", + "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/reporters/node_modules/jest-worker": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.3.tgz", + "integrity": "sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/reporters/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/@jest/reporters/node_modules/write-file-atomic": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.1.tgz", + "integrity": "sha512-nSKUxgAbyioruk6hU87QzVbY279oYT6uiwgDoujth2ju4mJ+TZau7SQBhtbTmUyuNYTuXnSyRn66FV0+eCgcrQ==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" + } + }, + "node_modules/@jest/schemas": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.1.3.tgz", + "integrity": "sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.24.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, "node_modules/@jest/source-map": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.4.0.tgz", - "integrity": "sha512-Ntjx9jzP26Bvhbm93z/AKcPRj/9wrkI88/gK60glXDx1q+IeI0rf7Lw2c89Ch6ofonB0On/iRDreQuQ6te9pgQ==", + "version": "28.1.2", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-28.1.2.tgz", + "integrity": "sha512-cV8Lx3BeStJb8ipPHnqVw/IM2VCMWO3crWZzYodSIkxXnRcXJipCdx1JCK0K5MsJJouZQTH73mzf4vgxRaH9ww==", "dev": true, "dependencies": { + "@jridgewell/trace-mapping": "^0.3.13", "callsites": "^3.0.0", - "graceful-fs": "^4.2.4", - "source-map": "^0.6.0" + "graceful-fs": "^4.2.9" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/@jest/test-result": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.4.2.tgz", - "integrity": "sha512-kr+bCrra9jfTgxHXHa2UwoQjxvQk3Am6QbpAiJ5x/50LW8llOYrxILkqY0lZRW/hu8FXesnudbql263+EW9iNA==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-28.1.3.tgz", + "integrity": "sha512-kZAkxnSE+FqE8YjW8gNuoVkkC9I7S1qmenl8sGcDOLropASP+BkcGKwhXoyqQuGOGeYY0y/ixjrd/iERpEXHNg==", "dev": true, "dependencies": { - "@jest/console": "^27.4.2", - "@jest/types": "^27.4.2", + "@jest/console": "^28.1.3", + "@jest/types": "^28.1.3", "@types/istanbul-lib-coverage": "^2.0.0", "collect-v8-coverage": "^1.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/@jest/test-sequencer": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.4.2.tgz", - "integrity": "sha512-HmHp5mlh9f9GyNej5yCS1JZIFfUGnP9+jEOH5zoq5EmsuZeYD+dGULqyvGDPtuzzbyAFJ6R4+z4SS0VvnFwwGQ==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-28.1.3.tgz", + "integrity": "sha512-NIMPEqqa59MWnDi1kvXXpYbqsfQmSJsIbnd85mdVGkiDfQ9WQQTXOLsvISUfonmnBT+w85WEgneCigEEdHDFxw==", "dev": true, "dependencies": { - "@jest/test-result": "^27.4.2", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.4.2", - "jest-runtime": "^27.4.2" + "@jest/test-result": "^28.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^28.1.3", + "slash": "^3.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, - "node_modules/@jest/transform": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.4.2.tgz", - "integrity": "sha512-RTKcPZllfcmLfnlxBya7aypofhdz05+E6QITe55Ex0rxyerkgjmmpMlvVn11V0cP719Ps6WcDYCnDzxnnJUwKg==", + "node_modules/@jest/test-sequencer/node_modules/jest-haste-map": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-28.1.3.tgz", + "integrity": "sha512-3S+RQWDXccXDKSWnkHa/dPwt+2qwA8CJzR61w3FoYCvoo3Pn8tvGcysmMF0Bj0EX5RYvAI2EIvC57OmotfdtKA==", "dev": true, "dependencies": { - "@babel/core": "^7.1.0", - "@jest/types": "^27.4.2", - "babel-plugin-istanbul": "^6.0.0", - "chalk": "^4.0.0", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.0.0", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.4.2", - "jest-regex-util": "^27.4.0", - "jest-util": "^27.4.2", + "@jest/types": "^28.1.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^28.0.2", + "jest-util": "^28.1.3", + "jest-worker": "^28.1.3", "micromatch": "^4.0.4", - "pirates": "^4.0.1", - "slash": "^3.0.0", - "source-map": "^0.6.1", - "write-file-atomic": "^3.0.0" + "walker": "^1.0.8" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/@jest/test-sequencer/node_modules/jest-regex-util": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", + "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/test-sequencer/node_modules/jest-worker": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.3.tgz", + "integrity": "sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/test-sequencer/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, "node_modules/@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", + "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", "dev": true, "dependencies": { + "@jest/schemas": "^28.1.3", "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^3.0.0", "@types/node": "*", - "@types/yargs": "^16.0.0", + "@types/yargs": "^17.0.8", "chalk": "^4.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.14", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz", + "integrity": "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "node_modules/@sinclair/typebox": { + "version": "0.24.22", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.22.tgz", + "integrity": "sha512-JsBe3cOFpNZ6yjBYnXKhcENWy5qZE3PQZwExQ5ksA/h8qp4bwwxFmy07A6bC2R6qv6+RF3SfrbQTskTwYNTXUQ==", + "dev": true + }, "node_modules/@sinonjs/commons": { "version": "1.8.3", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", @@ -990,18 +1310,18 @@ } }, "node_modules/@sinonjs/fake-timers": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz", - "integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==", + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", + "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", "dev": true, "dependencies": { "@sinonjs/commons": "^1.7.0" } }, "node_modules/@snowtop/ent": { - "version": "0.1.0-alpha51", - "resolved": "https://registry.npmjs.org/@snowtop/ent/-/ent-0.1.0-alpha51.tgz", - "integrity": "sha512-C5P5HK/lEnNZqQXExsXDj1Bth26jAFVlOsANxC/9O4aszVCgyZeMFe/K9Cm2ZffGeCa+h4AuJM66JF+wzZDtgw==", + "version": "0.1.0-alpha55", + "resolved": "https://registry.npmjs.org/@snowtop/ent/-/ent-0.1.0-alpha55.tgz", + "integrity": "sha512-L0tI3r2YARhfiOkUMRCzTBISuoZU4Xji7/+Z/huLxLKMDN/KV2UL9OFNgcxns7JFNKaIRF70ciRK2QjuEgNveQ==", "dependencies": { "@types/node": "^15.0.2", "camel-case": "^4.1.2", @@ -1070,23 +1390,14 @@ } }, "node_modules/@snowtop/ent-soft-delete": { - "version": "0.1.0-alpha1", - "resolved": "https://registry.npmjs.org/@snowtop/ent-soft-delete/-/ent-soft-delete-0.1.0-alpha1.tgz", - "integrity": "sha512-f6JngJw16HRgZ6G0chDqOOJ6vOkulbbHWz5IpOA87HbptGe2SjpBuuNiyEMYOe+Krtr1lUjw/knbIw2aEJTFlg==", + "version": "0.1.0-alpha3", + "resolved": "https://registry.npmjs.org/@snowtop/ent-soft-delete/-/ent-soft-delete-0.1.0-alpha3.tgz", + "integrity": "sha512-CnBb3iVcsXT8CjgE5ukH5rSDqX9+pymYX+mixA1SlvCDoaC1y6TzC23eaN1Q0ndrnPT7VKuFF40wqzLMnBVmjw==", "dependencies": { "@types/express": "^4.17.13" }, "peerDependencies": { - "@snowtop/ent": ">= 0.1.0-alpha20" - } - }, - "node_modules/@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", - "dev": true, - "engines": { - "node": ">= 6" + "@snowtop/ent": ">= 0.1.0-alpha55" } }, "node_modules/@tsconfig/node10": { @@ -1228,13 +1539,13 @@ } }, "node_modules/@types/jest": { - "version": "27.0.1", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.0.1.tgz", - "integrity": "sha512-HTLpVXHrY69556ozYkcq47TtQJXpcWAWfkoqz+ZGz2JnmZhzlRjprCIyFnetSy8gpDWwTTGBcRVv1J1I1vBrHw==", + "version": "28.1.6", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-28.1.6.tgz", + "integrity": "sha512-0RbGAFMfcBJKOmqRazM8L98uokwuwD5F8rHrv/ZMbrZBwVOWZUyPG6VFNscjYr/vjM3Vu4fRrCPbOs42AfemaQ==", "dev": true, "dependencies": { - "jest-diff": "^27.0.0", - "pretty-format": "^27.0.0" + "jest-matcher-utils": "^28.0.0", + "pretty-format": "^28.0.0" } }, "node_modules/@types/jest-expect-message": { @@ -1272,9 +1583,9 @@ } }, "node_modules/@types/prettier": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.2.tgz", - "integrity": "sha512-ekoj4qOQYp7CvjX8ZDBgN86w3MqQhLE1hczEJbEIjgFEumDy+na/4AJAbLXfgEWFNB2pKadM5rPFtuSGMWK7xA==", + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.6.4.tgz", + "integrity": "sha512-fOwvpvQYStpb/zHMx0Cauwywu9yLDmzWiiQBC7gJyq5tYLUXFZvDG7VK1B7WBxxjBJNKFOZ0zLoOQn8vmATbhw==", "dev": true }, "node_modules/@types/qs": { @@ -1328,24 +1639,18 @@ "dev": true }, "node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "version": "17.0.10", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", + "integrity": "sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA==", "dev": true, "dependencies": { "@types/yargs-parser": "*" } }, "node_modules/@types/yargs-parser": { - "version": "20.2.1", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.1.tgz", - "integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==", - "dev": true - }, - "node_modules/abab": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", - "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==", + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", "dev": true }, "node_modules/accepts": { @@ -1371,72 +1676,6 @@ "node": ">=0.4.0" } }, - "node_modules/acorn-globals": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", - "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", - "dev": true, - "dependencies": { - "acorn": "^7.1.1", - "acorn-walk": "^7.1.1" - } - }, - "node_modules/acorn-globals/node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-walk": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", - "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/agent-base/node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/agent-base/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/ansi-escapes": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", @@ -1524,59 +1763,22 @@ "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", "dev": true }, - "node_modules/babel-jest": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.4.2.tgz", - "integrity": "sha512-MADrjb3KBO2eyZCAc6QaJg6RT5u+6oEdDyHO5HEalnpwQ6LrhTsQF2Kj1Wnz2t6UPXIXPk18dSXXOT0wF5yTxA==", - "dev": true, - "dependencies": { - "@jest/transform": "^27.4.2", - "@jest/types": "^27.4.2", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.0.0", - "babel-preset-jest": "^27.4.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "slash": "^3.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.8.0" - } - }, - "node_modules/babel-plugin-istanbul": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz", - "integrity": "sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ==", + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@istanbuljs/load-nyc-config": "^1.0.0", "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^4.0.0", + "istanbul-lib-instrument": "^5.0.4", "test-exclude": "^6.0.0" }, "engines": { "node": ">=8" } }, - "node_modules/babel-plugin-jest-hoist": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.4.0.tgz", - "integrity": "sha512-Jcu7qS4OX5kTWBc45Hz7BMmgXuJqRnhatqpUhnzGC3OBYpOmf2tv6jFNwZpwM7wU7MUuv2r9IPS/ZlYOuburVw==", - "dev": true, - "dependencies": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.0.0", - "@types/babel__traverse": "^7.0.6" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, "node_modules/babel-preset-current-node-syntax": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", @@ -1600,22 +1802,6 @@ "@babel/core": "^7.0.0" } }, - "node_modules/babel-preset-jest": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.4.0.tgz", - "integrity": "sha512-NK4jGYpnBvNxcGo7/ZpZJr51jCGT+3bwwpVIDY2oNfTxJJldRtB4VAcYdgp1loDE50ODuTu+yBjpMAswv5tlpg==", - "dev": true, - "dependencies": { - "babel-plugin-jest-hoist": "^27.4.0", - "babel-preset-current-node-syntax": "^1.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -1723,12 +1909,6 @@ "node": ">=8" } }, - "node_modules/browser-process-hrtime": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", - "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", - "dev": true - }, "node_modules/browserslist": { "version": "4.17.0", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.0.tgz", @@ -1950,7 +2130,7 @@ "node_modules/co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", "dev": true, "engines": { "iojs": ">= 1.0.0", @@ -2113,30 +2293,6 @@ "node": ">= 8" } }, - "node_modules/cssom": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", - "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", - "dev": true - }, - "node_modules/cssstyle": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", - "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", - "dev": true, - "dependencies": { - "cssom": "~0.3.6" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cssstyle/node_modules/cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", - "dev": true - }, "node_modules/d": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", @@ -2146,20 +2302,6 @@ "type": "^1.0.1" } }, - "node_modules/data-urls": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", - "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", - "dev": true, - "dependencies": { - "abab": "^2.0.3", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/dataloader": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/dataloader/-/dataloader-2.1.0.tgz", @@ -2173,12 +2315,6 @@ "ms": "2.0.0" } }, - "node_modules/decimal.js": { - "version": "10.3.1", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz", - "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==", - "dev": true - }, "node_modules/decompress-response": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", @@ -2193,7 +2329,7 @@ "node_modules/dedent": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", + "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", "dev": true }, "node_modules/deep-extend": { @@ -2204,12 +2340,6 @@ "node": ">=4.0.0" } }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, "node_modules/deepmerge": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", @@ -2274,36 +2404,6 @@ "node": ">=0.3.1" } }, - "node_modules/diff-sequences": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.4.0.tgz", - "integrity": "sha512-YqiQzkrsmHMH5uuh8OdQFU9/ZpADnwzml8z0O5HvRNda+5UZsaX/xN+AAxfR2hWq1Y7HZnAzO9J5lJXOuDz2Ww==", - "dev": true, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/domexception": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", - "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", - "dev": true, - "dependencies": { - "webidl-conversions": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/domexception/node_modules/webidl-conversions": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", - "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/dot-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", @@ -2325,12 +2425,12 @@ "dev": true }, "node_modules/emittery": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", - "integrity": "sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==", + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.10.2.tgz", + "integrity": "sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw==", "dev": true, "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { "url": "https://github.com/sindresorhus/emittery?sponsor=1" @@ -2358,6 +2458,15 @@ "once": "^1.4.0" } }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, "node_modules/es5-ext": { "version": "0.10.61", "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.61.tgz", @@ -2402,256 +2511,6 @@ "es6-symbol": "^3.1.1" } }, - "node_modules/esbuild": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.2.tgz", - "integrity": "sha512-l076A6o/PIgcyM24s0dWmDI/b8RQf41uWoJu9I0M71CtW/YSw5T5NUeXxs5lo2tFQD+O4CW4nBHJXx3OY5NpXg==", - "dev": true, - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "optionalDependencies": { - "esbuild-android-arm64": "0.14.2", - "esbuild-darwin-64": "0.14.2", - "esbuild-darwin-arm64": "0.14.2", - "esbuild-freebsd-64": "0.14.2", - "esbuild-freebsd-arm64": "0.14.2", - "esbuild-linux-32": "0.14.2", - "esbuild-linux-64": "0.14.2", - "esbuild-linux-arm": "0.14.2", - "esbuild-linux-arm64": "0.14.2", - "esbuild-linux-mips64le": "0.14.2", - "esbuild-linux-ppc64le": "0.14.2", - "esbuild-netbsd-64": "0.14.2", - "esbuild-openbsd-64": "0.14.2", - "esbuild-sunos-64": "0.14.2", - "esbuild-windows-32": "0.14.2", - "esbuild-windows-64": "0.14.2", - "esbuild-windows-arm64": "0.14.2" - } - }, - "node_modules/esbuild-android-arm64": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.2.tgz", - "integrity": "sha512-hEixaKMN3XXCkoe+0WcexO4CcBVU5DCSUT+7P8JZiWZCbAjSkc9b6Yz2X5DSfQmRCtI/cQRU6TfMYrMQ5NBfdw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/esbuild-darwin-64": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.2.tgz", - "integrity": "sha512-Uq8t0cbJQkxkQdbUfOl2wZqZ/AtLZjvJulR1HHnc96UgyzG9YlCLSDMiqjM+NANEy7/zzvwKJsy3iNC9wwqLJA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/esbuild-darwin-arm64": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.2.tgz", - "integrity": "sha512-619MSa17sr7YCIrUj88KzQu2ESA4jKYtIYfLU/smX6qNgxQt3Y/gzM4s6sgJ4fPQzirvmXgcHv1ZNQAs/Xh48A==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/esbuild-freebsd-64": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.2.tgz", - "integrity": "sha512-aP6FE/ZsChZpUV6F3HE3x1Pz0paoYXycJ7oLt06g0G9dhJKknPawXCqQg/WMyD+ldCEZfo7F1kavenPdIT/SGQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/esbuild-freebsd-arm64": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.2.tgz", - "integrity": "sha512-LSm98WTb1QIhyS83+Po0KTpZNdd2XpVpI9ua5rLWqKWbKeNRFwOsjeiuwBaRNc+O32s9oC2ZMefETxHBV6VNkQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/esbuild-linux-32": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.2.tgz", - "integrity": "sha512-8VxnNEyeUbiGflTKcuVc5JEPTqXfsx2O6ABwUbfS1Hp26lYPRPC7pKQK5Dxa0MBejGc50jy7YZae3EGQUQ8EkQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/esbuild-linux-64": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.2.tgz", - "integrity": "sha512-4bzMS2dNxOJoFIiHId4w+tqQzdnsch71JJV1qZnbnErSFWcR9lRgpSqWnTTFtv6XM+MvltRzSXC5wQ7AEBY6Hg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/esbuild-linux-arm": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.2.tgz", - "integrity": "sha512-PaylahvMHhH8YMfJPMKEqi64qA0Su+d4FNfHKvlKes/2dUe4QxgbwXT9oLVgy8iJdcFMrO7By4R8fS8S0p8aVQ==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/esbuild-linux-arm64": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.2.tgz", - "integrity": "sha512-RlIVp0RwJrdtasDF1vTFueLYZ8WuFzxoQ1OoRFZOTyJHCGCNgh7xJIC34gd7B7+RT0CzLBB4LcM5n0LS+hIoww==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/esbuild-linux-mips64le": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.2.tgz", - "integrity": "sha512-Fdwrq2roFnO5oetIiUQQueZ3+5soCxBSJswg3MvYaXDomj47BN6oAWMZgLrFh1oVrtWrxSDLCJBenYdbm2s+qQ==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/esbuild-linux-ppc64le": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.2.tgz", - "integrity": "sha512-vxptskw8JfCDD9QqpRO0XnsM1osuWeRjPaXX1TwdveLogYsbdFtcuiuK/4FxGiNMUr1ojtnCS2rMPbY8puc5NA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/esbuild-netbsd-64": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.2.tgz", - "integrity": "sha512-I8+LzYK5iSNpspS9eCV9sW67Rj8FgMHimGri4mKiGAmN0pNfx+hFX146rYtzGtewuxKtTsPywWteHx+hPRLDsw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ] - }, - "node_modules/esbuild-openbsd-64": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.2.tgz", - "integrity": "sha512-120HgMe9elidWUvM2E6mMf0csrGwx8sYDqUIJugyMy1oHm+/nT08bTAVXuwYG/rkMIqsEO9AlMxuYnwR6En/3Q==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ] - }, - "node_modules/esbuild-sunos-64": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.2.tgz", - "integrity": "sha512-Q3xcf9Uyfra9UuCFxoLixVvdigo0daZaKJ97TL2KNA4bxRUPK18wwGUk3AxvgDQZpRmg82w9PnkaNYo7a+24ow==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ] - }, - "node_modules/esbuild-windows-32": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.2.tgz", - "integrity": "sha512-TW7O49tPsrq+N1sW8mb3m24j/iDGa4xzAZH4wHWwoIzgtZAYPKC0hpIhufRRG/LA30bdMChO9pjJZ5mtcybtBQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/esbuild-windows-64": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.2.tgz", - "integrity": "sha512-Rym6ViMNmi1E2QuQMWy0AFAfdY0wGwZD73BnzlsQBX5hZBuy/L+Speh7ucUZ16gwsrMM9v86icZUDrSN/lNBKg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/esbuild-windows-arm64": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.2.tgz", - "integrity": "sha512-ZrLbhr0vX5Em/P1faMnHucjVVWPS+m3tktAtz93WkMZLmbRJevhiW1y4CbulBd2z0MEdXZ6emDa1zFHq5O5bSA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, "node_modules/escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -2675,28 +2534,6 @@ "node": ">=8" } }, - "node_modules/escodegen": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", - "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", - "dev": true, - "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" - }, - "engines": { - "node": ">=6.0" - }, - "optionalDependencies": { - "source-map": "~0.6.1" - } - }, "node_modules/esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", @@ -2710,24 +2547,6 @@ "node": ">=4" } }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", @@ -2771,7 +2590,7 @@ "node_modules/exit": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", "dev": true, "engines": { "node": ">= 0.8.0" @@ -2786,32 +2605,28 @@ } }, "node_modules/expect": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/expect/-/expect-27.4.2.tgz", - "integrity": "sha512-BjAXIDC6ZOW+WBFNg96J22D27Nq5ohn+oGcuP2rtOtcjuxNoV9McpQ60PcQWhdFOSBIQdR72e+4HdnbZTFSTyg==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/expect/-/expect-28.1.3.tgz", + "integrity": "sha512-eEh0xn8HlsuOBxFgIss+2mX85VAS4Qy3OSkjV7rlBWljtA4oWH37glVGyOZSZvErDT/yBywZdPGwCXuTvSG85g==", "dev": true, "dependencies": { - "@jest/types": "^27.4.2", - "ansi-styles": "^5.0.0", - "jest-get-type": "^27.4.0", - "jest-matcher-utils": "^27.4.2", - "jest-message-util": "^27.4.2", - "jest-regex-util": "^27.4.0" + "@jest/expect-utils": "^28.1.3", + "jest-get-type": "^28.0.2", + "jest-matcher-utils": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-util": "^28.1.3" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, - "node_modules/expect/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "node_modules/expect/node_modules/jest-get-type": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", + "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", "dev": true, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/express": { @@ -2892,12 +2707,6 @@ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "dev": true }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, "node_modules/fast-safe-stringify": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", @@ -3161,9 +2970,9 @@ } }, "node_modules/graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", "dev": true }, "node_modules/graph-data-structure": { @@ -3225,18 +3034,6 @@ "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" }, - "node_modules/html-encoding-sniffer": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", - "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", - "dev": true, - "dependencies": { - "whatwg-encoding": "^1.0.5" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", @@ -3266,94 +3063,21 @@ "node": ">=0.6" } }, - "node_modules/http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true, - "dependencies": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" - }, "engines": { - "node": ">= 6" + "node": ">=10.17.0" } }, - "node_modules/http-proxy-agent/node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dev": true, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/http-proxy-agent/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", - "dev": true, - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/https-proxy-agent/node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/https-proxy-agent/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" + "safer-buffer": ">= 2.1.2 < 3" }, "engines": { "node": ">=0.10.0" @@ -3379,9 +3103,9 @@ ] }, "node_modules/import-local": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.3.tgz", - "integrity": "sha512-bE9iaUY3CXH8Cwfan/abDKAxe1KGT9kyGsBPqf6DMK/z0a2OzAsrukeYNgIH6cH5Xr452jb1TUL8rSfCLjZ9uA==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", "dev": true, "dependencies": { "pkg-dir": "^4.2.0", @@ -3392,6 +3116,9 @@ }, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/imurmurhash": { @@ -3430,10 +3157,16 @@ "node": ">= 0.10" } }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, "node_modules/is-core-module": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", - "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", + "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", "dev": true, "dependencies": { "has": "^1.0.3" @@ -3471,12 +3204,6 @@ "node": ">=0.12.0" } }, - "node_modules/is-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "dev": true - }, "node_modules/is-promise": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", @@ -3494,12 +3221,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, "node_modules/isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -3508,27 +3229,28 @@ "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, "node_modules/istanbul-lib-coverage": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", - "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", "dev": true, "engines": { "node": ">=8" } }, "node_modules/istanbul-lib-instrument": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", - "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz", + "integrity": "sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A==", "dev": true, "dependencies": { - "@babel/core": "^7.7.5", + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-coverage": "^3.2.0", "semver": "^6.3.0" }, "engines": { @@ -3564,9 +3286,9 @@ } }, "node_modules/istanbul-lib-source-maps/node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "dependencies": { "ms": "2.1.2" @@ -3587,9 +3309,9 @@ "dev": true }, "node_modules/istanbul-reports": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.1.tgz", - "integrity": "sha512-q1kvhAXWSsXfMjCdNHNPKZZv94OlspKnoGv+R9RGbnqOOQ0VbNfLFgQDVgi7hHenKsndGq3/o0OBdzDXthWcNw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", + "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", "dev": true, "dependencies": { "html-escaper": "^2.0.0", @@ -3600,20 +3322,21 @@ } }, "node_modules/jest": { - "version": "27.4.3", - "resolved": "https://registry.npmjs.org/jest/-/jest-27.4.3.tgz", - "integrity": "sha512-jwsfVABBzuN3Atm+6h6vIEpTs9+VApODLt4dk2qv1WMOpb1weI1IIZfuwpMiWZ62qvWj78MvdvMHIYdUfqrFaA==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest/-/jest-28.1.3.tgz", + "integrity": "sha512-N4GT5on8UkZgH0O5LUavMRV1EDEhNTL0KEfRmDIeZHSV7p2XgLoY9t9VDUgL6o+yfdgYHVxuz81G8oB9VG5uyA==", "dev": true, "dependencies": { - "@jest/core": "^27.4.3", + "@jest/core": "^28.1.3", + "@jest/types": "^28.1.3", "import-local": "^3.0.2", - "jest-cli": "^27.4.3" + "jest-cli": "^28.1.3" }, "bin": { "jest": "bin/jest.js" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" }, "peerDependencies": { "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" @@ -3625,73 +3348,102 @@ } }, "node_modules/jest-changed-files": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.4.2.tgz", - "integrity": "sha512-/9x8MjekuzUQoPjDHbBiXbNEBauhrPU2ct7m8TfCg69ywt1y/N+yYwGh3gCpnqUS3klYWDU/lSNgv+JhoD2k1A==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-28.1.3.tgz", + "integrity": "sha512-esaOfUWJXk2nfZt9SPyC8gA1kNfdKLkQWyzsMlqq8msYSlNKfmZxfRgZn4Cd4MGVUF+7v6dBs0d5TOAKa7iIiA==", "dev": true, "dependencies": { - "@jest/types": "^27.4.2", "execa": "^5.0.0", - "throat": "^6.0.1" + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-changed-files/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/jest-circus": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.4.2.tgz", - "integrity": "sha512-2ePUSru1BGMyzxsMvRfu+tNb+PW60rUyMLJBfw1Nrh5zC8RoTPfF+zbE0JToU31a6ZVe4nnrNKWYRzlghAbL0A==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-28.1.3.tgz", + "integrity": "sha512-cZ+eS5zc79MBwt+IhQhiEp0OeBddpc1n8MBo1nMB8A7oPMKEO+Sre+wHaLJexQUj9Ya/8NOBY0RESUgYjB6fow==", "dev": true, "dependencies": { - "@jest/environment": "^27.4.2", - "@jest/test-result": "^27.4.2", - "@jest/types": "^27.4.2", + "@jest/environment": "^28.1.3", + "@jest/expect": "^28.1.3", + "@jest/test-result": "^28.1.3", + "@jest/types": "^28.1.3", "@types/node": "*", "chalk": "^4.0.0", "co": "^4.6.0", "dedent": "^0.7.0", - "expect": "^27.4.2", "is-generator-fn": "^2.0.0", - "jest-each": "^27.4.2", - "jest-matcher-utils": "^27.4.2", - "jest-message-util": "^27.4.2", - "jest-runtime": "^27.4.2", - "jest-snapshot": "^27.4.2", - "jest-util": "^27.4.2", - "pretty-format": "^27.4.2", + "jest-each": "^28.1.3", + "jest-matcher-utils": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-runtime": "^28.1.3", + "jest-snapshot": "^28.1.3", + "jest-util": "^28.1.3", + "p-limit": "^3.1.0", + "pretty-format": "^28.1.3", "slash": "^3.0.0", - "stack-utils": "^2.0.3", - "throat": "^6.0.1" + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-circus/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/jest-cli": { - "version": "27.4.3", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.4.3.tgz", - "integrity": "sha512-zZSJBXNC/i8UnJPwcKWsqnhGgIF3uoTYP7th32Zej7KNQJdxzOMj+wCfy2Ox3kU7nXErJ36DtYyXDhfiqaiDRw==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-28.1.3.tgz", + "integrity": "sha512-roY3kvrv57Azn1yPgdTebPAXvdR2xfezaKKYzVxZ6It/5NCxzJym6tUI5P1zkdWhfUYkxEI9uZWcQdaFLo8mJQ==", "dev": true, "dependencies": { - "@jest/core": "^27.4.3", - "@jest/test-result": "^27.4.2", - "@jest/types": "^27.4.2", + "@jest/core": "^28.1.3", + "@jest/test-result": "^28.1.3", + "@jest/types": "^28.1.3", "chalk": "^4.0.0", "exit": "^0.1.2", - "graceful-fs": "^4.2.4", + "graceful-fs": "^4.2.9", "import-local": "^3.0.2", - "jest-config": "^27.4.3", - "jest-util": "^27.4.2", - "jest-validate": "^27.4.2", + "jest-config": "^28.1.3", + "jest-util": "^28.1.3", + "jest-validate": "^28.1.3", "prompts": "^2.0.1", - "yargs": "^16.2.0" + "yargs": "^17.3.1" }, "bin": { "jest": "bin/jest.js" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" }, "peerDependencies": { "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" @@ -3703,259 +3455,392 @@ } }, "node_modules/jest-config": { - "version": "27.4.3", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.4.3.tgz", - "integrity": "sha512-DQ10HTSqYtC2pO7s9j2jw+li4xUnm2wLYWH2o7K1ftB8NyvToHsXoLlXxtsGh3AW9gUQR6KY/4B7G+T/NswJBw==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-28.1.3.tgz", + "integrity": "sha512-MG3INjByJ0J4AsNBm7T3hsuxKQqFIiRo/AUqb1q9LRKI5UU6Aar9JHbr9Ivn1TVwfUD9KirRoM/T6u8XlcQPHQ==", "dev": true, "dependencies": { - "@babel/core": "^7.1.0", - "@jest/test-sequencer": "^27.4.2", - "@jest/types": "^27.4.2", - "babel-jest": "^27.4.2", + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^28.1.3", + "@jest/types": "^28.1.3", + "babel-jest": "^28.1.3", "chalk": "^4.0.0", "ci-info": "^3.2.0", "deepmerge": "^4.2.2", - "glob": "^7.1.1", - "graceful-fs": "^4.2.4", - "jest-circus": "^27.4.2", - "jest-environment-jsdom": "^27.4.3", - "jest-environment-node": "^27.4.2", - "jest-get-type": "^27.4.0", - "jest-jasmine2": "^27.4.2", - "jest-regex-util": "^27.4.0", - "jest-resolve": "^27.4.2", - "jest-runner": "^27.4.3", - "jest-util": "^27.4.2", - "jest-validate": "^27.4.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^28.1.3", + "jest-environment-node": "^28.1.3", + "jest-get-type": "^28.0.2", + "jest-regex-util": "^28.0.2", + "jest-resolve": "^28.1.3", + "jest-runner": "^28.1.3", + "jest-util": "^28.1.3", + "jest-validate": "^28.1.3", "micromatch": "^4.0.4", - "pretty-format": "^27.4.2", - "slash": "^3.0.0" + "parse-json": "^5.2.0", + "pretty-format": "^28.1.3", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" }, "peerDependencies": { + "@types/node": "*", "ts-node": ">=9.0.0" }, "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, "ts-node": { "optional": true } } }, - "node_modules/jest-date-mock": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/jest-date-mock/-/jest-date-mock-1.0.8.tgz", - "integrity": "sha512-0Lyp+z9xvuNmLbK+5N6FOhSiBeux05Lp5bbveFBmYo40Aggl2wwxFoIrZ+rOWC8nDNcLeBoDd2miQdEDSf3iQw==", - "dev": true + "node_modules/jest-config/node_modules/@jest/transform": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-28.1.3.tgz", + "integrity": "sha512-u5dT5di+oFI6hfcLOHGTAfmUxFRrjK+vnaP0kkVow9Md/M7V/MxqQMOz/VV25UZO8pzeA9PjfTpOu6BDuwSPQA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^28.1.3", + "@jridgewell/trace-mapping": "^0.3.13", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^28.1.3", + "jest-regex-util": "^28.0.2", + "jest-util": "^28.1.3", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } }, - "node_modules/jest-diff": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.4.2.tgz", - "integrity": "sha512-ujc9ToyUZDh9KcqvQDkk/gkbf6zSaeEg9AiBxtttXW59H/AcqEYp1ciXAtJp+jXWva5nAf/ePtSsgWwE5mqp4Q==", + "node_modules/jest-config/node_modules/babel-jest": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-28.1.3.tgz", + "integrity": "sha512-epUaPOEWMk3cWX0M/sPvCHHCe9fMFAa/9hXEgKP8nFfNl/jlGkE9ucq9NqkZGXLDduCJYS0UvSlPUwC0S+rH6Q==", "dev": true, "dependencies": { + "@jest/transform": "^28.1.3", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^28.1.3", "chalk": "^4.0.0", - "diff-sequences": "^27.4.0", - "jest-get-type": "^27.4.0", - "pretty-format": "^27.4.2" + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" } }, - "node_modules/jest-docblock": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.4.0.tgz", - "integrity": "sha512-7TBazUdCKGV7svZ+gh7C8esAnweJoG+SvcF6Cjqj4l17zA2q1cMwx2JObSioubk317H+cjcHgP+7fTs60paulg==", + "node_modules/jest-config/node_modules/babel-plugin-jest-hoist": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-28.1.3.tgz", + "integrity": "sha512-Ys3tUKAmfnkRUpPdpa98eYrAR0nV+sSFUZZEGuQ2EbFd1y4SOLtD5QDNHAq+bb9a+bbXvYQC4b+ID/THIMcU6Q==", "dev": true, "dependencies": { - "detect-newline": "^3.0.0" + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, - "node_modules/jest-each": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.4.2.tgz", - "integrity": "sha512-53V2MNyW28CTruB3lXaHNk6PkiIFuzdOC9gR3C6j8YE/ACfrPnz+slB0s17AgU1TtxNzLuHyvNlLJ+8QYw9nBg==", + "node_modules/jest-config/node_modules/babel-preset-jest": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-28.1.3.tgz", + "integrity": "sha512-L+fupJvlWAHbQfn74coNX3zf60LXMJsezNvvx8eIh7iOR1luJ1poxYgQk1F8PYtNq/6QODDHCqsSnTFSWC491A==", "dev": true, "dependencies": { - "@jest/types": "^27.4.2", - "chalk": "^4.0.0", - "jest-get-type": "^27.4.0", - "jest-util": "^27.4.2", - "pretty-format": "^27.4.2" + "babel-plugin-jest-hoist": "^28.1.3", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/jest-config/node_modules/jest-get-type": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", + "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "dev": true, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, - "node_modules/jest-environment-jsdom": { - "version": "27.4.3", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.4.3.tgz", - "integrity": "sha512-x1AUVz3G14LpEJs7KIFUaTINT2n0unOUmvdAby3s/sldUpJJetOJifHo1O/EUQC5fNBowggwJbVulko18y6OWw==", + "node_modules/jest-config/node_modules/jest-haste-map": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-28.1.3.tgz", + "integrity": "sha512-3S+RQWDXccXDKSWnkHa/dPwt+2qwA8CJzR61w3FoYCvoo3Pn8tvGcysmMF0Bj0EX5RYvAI2EIvC57OmotfdtKA==", "dev": true, "dependencies": { - "@jest/environment": "^27.4.2", - "@jest/fake-timers": "^27.4.2", - "@jest/types": "^27.4.2", + "@jest/types": "^28.1.3", + "@types/graceful-fs": "^4.1.3", "@types/node": "*", - "jest-mock": "^27.4.2", - "jest-util": "^27.4.2", - "jsdom": "^16.6.0" + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^28.0.2", + "jest-util": "^28.1.3", + "jest-worker": "^28.1.3", + "micromatch": "^4.0.4", + "walker": "^1.0.8" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" } }, - "node_modules/jest-environment-node": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.4.2.tgz", - "integrity": "sha512-nzTZ5nJ+FabuZPH2YVci7SZIHpvtNRHPt8+vipLkCnAgXGjVzHm7XJWdnNqXbAkExIgiKeVEkVMNZOZE/LeiIg==", + "node_modules/jest-config/node_modules/jest-regex-util": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", + "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-config/node_modules/jest-worker": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.3.tgz", + "integrity": "sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==", "dev": true, "dependencies": { - "@jest/environment": "^27.4.2", - "@jest/fake-timers": "^27.4.2", - "@jest/types": "^27.4.2", "@types/node": "*", - "jest-mock": "^27.4.2", - "jest-util": "^27.4.2" + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, - "node_modules/jest-expect-message": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/jest-expect-message/-/jest-expect-message-1.0.2.tgz", - "integrity": "sha512-WFiXMgwS2lOqQZt1iJMI/hOXpUm32X+ApsuzYcQpW5m16Pv6/Gd9kgC+Q+Q1YVNU04kYcAOv9NXMnjg6kKUy6Q==", - "dev": true + "node_modules/jest-config/node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "node_modules/jest-get-type": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.4.0.tgz", - "integrity": "sha512-tk9o+ld5TWq41DkK14L4wox4s2D9MtTpKaAVzXfr5CUKm5ZK2ExcaFE0qls2W71zE/6R2TxxrK9w2r6svAFDBQ==", + "node_modules/jest-config/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/jest-haste-map": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.4.2.tgz", - "integrity": "sha512-foiyAEePORUN2eeJnOtcM1y8qW0ShEd9kTjWVL4sVaMcuCJM6gtHegvYPBRT0mpI/bs4ueThM90+Eoj2ncoNsA==", + "node_modules/jest-config/node_modules/write-file-atomic": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.1.tgz", + "integrity": "sha512-nSKUxgAbyioruk6hU87QzVbY279oYT6uiwgDoujth2ju4mJ+TZau7SQBhtbTmUyuNYTuXnSyRn66FV0+eCgcrQ==", "dev": true, "dependencies": { - "@jest/types": "^27.4.2", - "@types/graceful-fs": "^4.1.2", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.4", - "jest-regex-util": "^27.4.0", - "jest-serializer": "^27.4.0", - "jest-util": "^27.4.2", - "jest-worker": "^27.4.2", - "micromatch": "^4.0.4", - "walker": "^1.0.7" + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || >=16" + } + }, + "node_modules/jest-date-mock": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/jest-date-mock/-/jest-date-mock-1.0.8.tgz", + "integrity": "sha512-0Lyp+z9xvuNmLbK+5N6FOhSiBeux05Lp5bbveFBmYo40Aggl2wwxFoIrZ+rOWC8nDNcLeBoDd2miQdEDSf3iQw==", + "dev": true + }, + "node_modules/jest-docblock": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-28.1.1.tgz", + "integrity": "sha512-3wayBVNiOYx0cwAbl9rwm5kKFP8yHH3d/fkEaL02NPTkDojPtheGB7HZSFY4wzX+DxyrvhXz0KSCVksmCknCuA==", + "dev": true, + "dependencies": { + "detect-newline": "^3.0.0" }, - "optionalDependencies": { - "fsevents": "^2.3.2" + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-each": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-28.1.3.tgz", + "integrity": "sha512-arT1z4sg2yABU5uogObVPvSlSMQlDA48owx07BDPAiasW0yYpYHYOo4HHLz9q0BVzDVU4hILFjzJw0So9aCL/g==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.3", + "chalk": "^4.0.0", + "jest-get-type": "^28.0.2", + "jest-util": "^28.1.3", + "pretty-format": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-each/node_modules/jest-get-type": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", + "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, - "node_modules/jest-jasmine2": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.4.2.tgz", - "integrity": "sha512-VO/fyAJSH9u0THjbteFiL8qc93ufU+yW+bdieDc8tzTCWwlWzO53UHS5nFK1qmE8izb5Smkn+XHlVt6/l06MKQ==", + "node_modules/jest-environment-node": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-28.1.3.tgz", + "integrity": "sha512-ugP6XOhEpjAEhGYvp5Xj989ns5cB1K6ZdjBYuS30umT4CQEETaxSiPcZ/E1kFktX4GkrcM4qu07IIlDYX1gp+A==", "dev": true, "dependencies": { - "@babel/traverse": "^7.1.0", - "@jest/environment": "^27.4.2", - "@jest/source-map": "^27.4.0", - "@jest/test-result": "^27.4.2", - "@jest/types": "^27.4.2", + "@jest/environment": "^28.1.3", + "@jest/fake-timers": "^28.1.3", + "@jest/types": "^28.1.3", "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "expect": "^27.4.2", - "is-generator-fn": "^2.0.0", - "jest-each": "^27.4.2", - "jest-matcher-utils": "^27.4.2", - "jest-message-util": "^27.4.2", - "jest-runtime": "^27.4.2", - "jest-snapshot": "^27.4.2", - "jest-util": "^27.4.2", - "pretty-format": "^27.4.2", - "throat": "^6.0.1" + "jest-mock": "^28.1.3", + "jest-util": "^28.1.3" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, + "node_modules/jest-expect-message": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/jest-expect-message/-/jest-expect-message-1.0.2.tgz", + "integrity": "sha512-WFiXMgwS2lOqQZt1iJMI/hOXpUm32X+ApsuzYcQpW5m16Pv6/Gd9kgC+Q+Q1YVNU04kYcAOv9NXMnjg6kKUy6Q==", + "dev": true + }, "node_modules/jest-leak-detector": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.4.2.tgz", - "integrity": "sha512-ml0KvFYZllzPBJWDei3mDzUhyp/M4ubKebX++fPaudpe8OsxUE+m+P6ciVLboQsrzOCWDjE20/eXew9QMx/VGw==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-28.1.3.tgz", + "integrity": "sha512-WFVJhnQsiKtDEo5lG2mM0v40QWnBM+zMdHHyJs8AWZ7J0QZJS59MsyKeJHWhpBZBH32S48FOVvGyOFT1h0DlqA==", "dev": true, "dependencies": { - "jest-get-type": "^27.4.0", - "pretty-format": "^27.4.2" + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.3" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-leak-detector/node_modules/jest-get-type": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", + "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/jest-matcher-utils": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.4.2.tgz", - "integrity": "sha512-jyP28er3RRtMv+fmYC/PKG8wvAmfGcSNproVTW2Y0P/OY7/hWUOmsPfxN1jOhM+0u2xU984u2yEagGivz9OBGQ==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-28.1.3.tgz", + "integrity": "sha512-kQeJ7qHemKfbzKoGjHHrRKH6atgxMk8Enkk2iPQ3XwO6oE/KYD8lMYOziCkeSB9G4adPM4nR1DE8Tf5JeWH6Bw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^28.1.3", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/diff-sequences": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.1.1.tgz", + "integrity": "sha512-FU0iFaH/E23a+a718l8Qa/19bF9p06kgE0KipMOMadwa3SjnaElKzPaUC0vnibs6/B/9ni97s61mcejk8W1fQw==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/jest-diff": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.1.3.tgz", + "integrity": "sha512-8RqP1B/OXzjjTWkqMX67iqgwBVJRgCyKD3L9nq+6ZqJMdvjE8RgHktqZ6jNrkdMT+dJuYNI3rhQpxaz7drJHfw==", "dev": true, "dependencies": { "chalk": "^4.0.0", - "jest-diff": "^27.4.2", - "jest-get-type": "^27.4.0", - "pretty-format": "^27.4.2" + "diff-sequences": "^28.1.1", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.3" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/jest-get-type": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", + "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/jest-message-util": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.4.2.tgz", - "integrity": "sha512-OMRqRNd9E0DkBLZpFtZkAGYOXl6ZpoMtQJWTAREJKDOFa0M6ptB7L67tp+cszMBkvSgKOhNtQp2Vbcz3ZZKo/w==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.3.tgz", + "integrity": "sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g==", "dev": true, "dependencies": { "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.4.2", + "@jest/types": "^28.1.3", "@types/stack-utils": "^2.0.0", "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", + "graceful-fs": "^4.2.9", "micromatch": "^4.0.4", - "pretty-format": "^27.4.2", + "pretty-format": "^28.1.3", "slash": "^3.0.0", "stack-utils": "^2.0.3" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/jest-mock": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.4.2.tgz", - "integrity": "sha512-PDDPuyhoukk20JrQKeofK12hqtSka7mWH0QQuxSNgrdiPsrnYYLS6wbzu/HDlxZRzji5ylLRULeuI/vmZZDrYA==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-28.1.3.tgz", + "integrity": "sha512-o3J2jr6dMMWYVH4Lh/NKmDXdosrsJgi4AviS8oXLujcjpCMBb1FMsblDnOXKZKfSiHLxYub1eS0IHuRXsio9eA==", "dev": true, "dependencies": { - "@jest/types": "^27.4.2", + "@jest/types": "^28.1.3", "@types/node": "*" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/jest-pnp-resolver": { @@ -3975,222 +3860,225 @@ } } }, - "node_modules/jest-regex-util": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.4.0.tgz", - "integrity": "sha512-WeCpMpNnqJYMQoOjm1nTtsgbR4XHAk1u00qDoNBQoykM280+/TmgA5Qh5giC1ecy6a5d4hbSsHzpBtu5yvlbEg==", - "dev": true, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, "node_modules/jest-resolve": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.4.2.tgz", - "integrity": "sha512-d/zqPjxCzMqHlOdRTg8cTpO9jY+1/T74KazT8Ws/LwmwxV5sRMWOkiLjmzUCDj/5IqA5XHNK4Hkmlq9Kdpb9Sg==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-28.1.3.tgz", + "integrity": "sha512-Z1W3tTjE6QaNI90qo/BJpfnvpxtaFTFw5CDgwpyE/Kz8U/06N1Hjf4ia9quUhCh39qIGWF1ZuxFiBiJQwSEYKQ==", "dev": true, "dependencies": { - "@jest/types": "^27.4.2", "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.4.2", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^28.1.3", "jest-pnp-resolver": "^1.2.2", - "jest-util": "^27.4.2", - "jest-validate": "^27.4.2", + "jest-util": "^28.1.3", + "jest-validate": "^28.1.3", "resolve": "^1.20.0", "resolve.exports": "^1.1.0", "slash": "^3.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/jest-resolve-dependencies": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.4.2.tgz", - "integrity": "sha512-hb++cTpqvOWfU49MCP/JQkxmnrhKoAVqXWFjgYXswRSVGk8Q6bDTSvhbCeYXDtXaymY0y7WrrSIlKogClcKJuw==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-28.1.3.tgz", + "integrity": "sha512-qa0QO2Q0XzQoNPouMbCc7Bvtsem8eQgVPNkwn9LnS+R2n8DaVDPL/U1gngC0LTl1RYXJU0uJa2BMC2DbTfFrHA==", "dev": true, "dependencies": { - "@jest/types": "^27.4.2", - "jest-regex-util": "^27.4.0", - "jest-snapshot": "^27.4.2" + "jest-regex-util": "^28.0.2", + "jest-snapshot": "^28.1.3" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, - "node_modules/jest-runner": { - "version": "27.4.3", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.4.3.tgz", - "integrity": "sha512-JgR6Om/j22Fd6ZUUIGTWNcCtuZVYbNrecb4k89W4UyFJoRtHpo2zMKWkmFFFJoqwWGrfrcPLnVBIgkJiTV3cyA==", + "node_modules/jest-resolve-dependencies/node_modules/jest-regex-util": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", + "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==", "dev": true, - "dependencies": { - "@jest/console": "^27.4.2", - "@jest/environment": "^27.4.2", - "@jest/test-result": "^27.4.2", - "@jest/transform": "^27.4.2", - "@jest/types": "^27.4.2", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.8.1", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "jest-docblock": "^27.4.0", - "jest-environment-jsdom": "^27.4.3", - "jest-environment-node": "^27.4.2", - "jest-haste-map": "^27.4.2", - "jest-leak-detector": "^27.4.2", - "jest-message-util": "^27.4.2", - "jest-resolve": "^27.4.2", - "jest-runtime": "^27.4.2", - "jest-util": "^27.4.2", - "jest-worker": "^27.4.2", - "source-map-support": "^0.5.6", - "throat": "^6.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-runtime": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.4.2.tgz", - "integrity": "sha512-eqPgcBaUNaw6j8T5M+dnfAEh6MIrh2YmtskCr9sl50QYpD22Sg+QqHw3J3nmaLzVMbBtOMHFFxLF0Qx8MsZVFQ==", - "dev": true, - "dependencies": { - "@jest/console": "^27.4.2", - "@jest/environment": "^27.4.2", - "@jest/globals": "^27.4.2", - "@jest/source-map": "^27.4.0", - "@jest/test-result": "^27.4.2", - "@jest/transform": "^27.4.2", - "@jest/types": "^27.4.2", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "execa": "^5.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.4.2", - "jest-message-util": "^27.4.2", - "jest-mock": "^27.4.2", - "jest-regex-util": "^27.4.0", - "jest-resolve": "^27.4.2", - "jest-snapshot": "^27.4.2", - "jest-util": "^27.4.2", - "jest-validate": "^27.4.2", - "slash": "^3.0.0", - "strip-bom": "^4.0.0", - "yargs": "^16.2.0" - }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, - "node_modules/jest-serializer": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.4.0.tgz", - "integrity": "sha512-RDhpcn5f1JYTX2pvJAGDcnsNTnsV9bjYPU8xcV+xPwOXnUPOQwf4ZEuiU6G9H1UztH+OapMgu/ckEVwO87PwnQ==", + "node_modules/jest-resolve/node_modules/jest-haste-map": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-28.1.3.tgz", + "integrity": "sha512-3S+RQWDXccXDKSWnkHa/dPwt+2qwA8CJzR61w3FoYCvoo3Pn8tvGcysmMF0Bj0EX5RYvAI2EIvC57OmotfdtKA==", "dev": true, "dependencies": { + "@jest/types": "^28.1.3", + "@types/graceful-fs": "^4.1.3", "@types/node": "*", - "graceful-fs": "^4.2.4" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^28.0.2", + "jest-util": "^28.1.3", + "jest-worker": "^28.1.3", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" } }, - "node_modules/jest-snapshot": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.4.2.tgz", - "integrity": "sha512-DI7lJlNIu6WSQ+esqhnJzEzU70+dV+cNjoF1c+j5FagWEd3KtOyZvVliAH0RWNQ6KSnAAnKSU0qxJ8UXOOhuUQ==", + "node_modules/jest-resolve/node_modules/jest-regex-util": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", + "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-resolve/node_modules/jest-worker": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.3.tgz", + "integrity": "sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==", "dev": true, "dependencies": { - "@babel/core": "^7.7.2", - "@babel/generator": "^7.7.2", - "@babel/parser": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/traverse": "^7.7.2", - "@babel/types": "^7.0.0", - "@jest/transform": "^27.4.2", - "@jest/types": "^27.4.2", - "@types/babel__traverse": "^7.0.4", - "@types/prettier": "^2.1.5", - "babel-preset-current-node-syntax": "^1.0.0", - "chalk": "^4.0.0", - "expect": "^27.4.2", - "graceful-fs": "^4.2.4", - "jest-diff": "^27.4.2", - "jest-get-type": "^27.4.0", - "jest-haste-map": "^27.4.2", - "jest-matcher-utils": "^27.4.2", - "jest-message-util": "^27.4.2", - "jest-resolve": "^27.4.2", - "jest-util": "^27.4.2", - "natural-compare": "^1.4.0", - "pretty-format": "^27.4.2", - "semver": "^7.3.2" + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, - "node_modules/jest-snapshot/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "node_modules/jest-resolve/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" + "has-flag": "^4.0.0" }, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/jest-util": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.4.2.tgz", - "integrity": "sha512-YuxxpXU6nlMan9qyLuxHaMMOzXAl5aGZWCSzben5DhLHemYQxCc4YK+4L3ZrCutT8GPQ+ui9k5D8rUJoDioMnA==", + "node_modules/jest-runner": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-28.1.3.tgz", + "integrity": "sha512-GkMw4D/0USd62OVO0oEgjn23TM+YJa2U2Wu5zz9xsQB1MxWKDOlrnykPxnMsN0tnJllfLPinHTka61u0QhaxBA==", "dev": true, "dependencies": { - "@jest/types": "^27.4.2", + "@jest/console": "^28.1.3", + "@jest/environment": "^28.1.3", + "@jest/test-result": "^28.1.3", + "@jest/transform": "^28.1.3", + "@jest/types": "^28.1.3", "@types/node": "*", "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.4", - "picomatch": "^2.2.3" + "emittery": "^0.10.2", + "graceful-fs": "^4.2.9", + "jest-docblock": "^28.1.1", + "jest-environment-node": "^28.1.3", + "jest-haste-map": "^28.1.3", + "jest-leak-detector": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-resolve": "^28.1.3", + "jest-runtime": "^28.1.3", + "jest-util": "^28.1.3", + "jest-watcher": "^28.1.3", + "jest-worker": "^28.1.3", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-runner/node_modules/@jest/transform": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-28.1.3.tgz", + "integrity": "sha512-u5dT5di+oFI6hfcLOHGTAfmUxFRrjK+vnaP0kkVow9Md/M7V/MxqQMOz/VV25UZO8pzeA9PjfTpOu6BDuwSPQA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^28.1.3", + "@jridgewell/trace-mapping": "^0.3.13", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^28.1.3", + "jest-regex-util": "^28.0.2", + "jest-util": "^28.1.3", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.1" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, - "node_modules/jest-validate": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.4.2.tgz", - "integrity": "sha512-hWYsSUej+Fs8ZhOm5vhWzwSLmVaPAxRy+Mr+z5MzeaHm9AxUpXdoVMEW4R86y5gOobVfBsMFLk4Rb+QkiEpx1A==", + "node_modules/jest-runner/node_modules/jest-haste-map": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-28.1.3.tgz", + "integrity": "sha512-3S+RQWDXccXDKSWnkHa/dPwt+2qwA8CJzR61w3FoYCvoo3Pn8tvGcysmMF0Bj0EX5RYvAI2EIvC57OmotfdtKA==", "dev": true, "dependencies": { - "@jest/types": "^27.4.2", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^27.4.0", - "leven": "^3.1.0", - "pretty-format": "^27.4.2" + "@jest/types": "^28.1.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^28.0.2", + "jest-util": "^28.1.3", + "jest-worker": "^28.1.3", + "micromatch": "^4.0.4", + "walker": "^1.0.8" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" } }, - "node_modules/jest-validate/node_modules/camelcase": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.1.tgz", - "integrity": "sha512-tVI4q5jjFV5CavAU8DXfza/TJcZutVKo/5Foskmsqcm0MsL91moHvwiGNnqaa2o6PF/7yT5ikDRcVcl8Rj6LCA==", + "node_modules/jest-runner/node_modules/jest-regex-util": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", + "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==", "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-runner/node_modules/jest-worker": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.3.tgz", + "integrity": "sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-runner/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, "engines": { "node": ">=10" }, @@ -4198,28 +4086,131 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-watcher": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.4.2.tgz", - "integrity": "sha512-NJvMVyyBeXfDezhWzUOCOYZrUmkSCiatpjpm+nFUid74OZEHk6aMLrZAukIiFDwdbqp6mTM6Ui1w4oc+8EobQg==", + "node_modules/jest-runner/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, "dependencies": { - "@jest/test-result": "^27.4.2", - "@jest/types": "^27.4.2", - "@types/node": "*", - "ansi-escapes": "^4.2.1", + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/jest-runner/node_modules/write-file-atomic": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.1.tgz", + "integrity": "sha512-nSKUxgAbyioruk6hU87QzVbY279oYT6uiwgDoujth2ju4mJ+TZau7SQBhtbTmUyuNYTuXnSyRn66FV0+eCgcrQ==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" + } + }, + "node_modules/jest-runtime": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-28.1.3.tgz", + "integrity": "sha512-NU+881ScBQQLc1JHG5eJGU7Ui3kLKrmwCPPtYsJtBykixrM2OhVQlpMmFWJjMyDfdkGgBMNjXCGB/ebzsgNGQw==", + "dev": true, + "dependencies": { + "@jest/environment": "^28.1.3", + "@jest/fake-timers": "^28.1.3", + "@jest/globals": "^28.1.3", + "@jest/source-map": "^28.1.2", + "@jest/test-result": "^28.1.3", + "@jest/transform": "^28.1.3", + "@jest/types": "^28.1.3", "chalk": "^4.0.0", - "jest-util": "^27.4.2", - "string-length": "^4.0.1" + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "execa": "^5.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-mock": "^28.1.3", + "jest-regex-util": "^28.0.2", + "jest-resolve": "^28.1.3", + "jest-snapshot": "^28.1.3", + "jest-util": "^28.1.3", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-runtime/node_modules/@jest/transform": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-28.1.3.tgz", + "integrity": "sha512-u5dT5di+oFI6hfcLOHGTAfmUxFRrjK+vnaP0kkVow9Md/M7V/MxqQMOz/VV25UZO8pzeA9PjfTpOu6BDuwSPQA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^28.1.3", + "@jridgewell/trace-mapping": "^0.3.13", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^28.1.3", + "jest-regex-util": "^28.0.2", + "jest-util": "^28.1.3", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.1" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, - "node_modules/jest-worker": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.4.2.tgz", - "integrity": "sha512-0QMy/zPovLfUPyHuOuuU4E+kGACXXE84nRnq6lBVI9GJg5DCBiA97SATi+ZP8CpiJwEQy1oCPjRBf8AnLjN+Ag==", + "node_modules/jest-runtime/node_modules/jest-haste-map": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-28.1.3.tgz", + "integrity": "sha512-3S+RQWDXccXDKSWnkHa/dPwt+2qwA8CJzR61w3FoYCvoo3Pn8tvGcysmMF0Bj0EX5RYvAI2EIvC57OmotfdtKA==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^28.0.2", + "jest-util": "^28.1.3", + "jest-worker": "^28.1.3", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-runtime/node_modules/jest-regex-util": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", + "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-runtime/node_modules/jest-worker": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.3.tgz", + "integrity": "sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==", "dev": true, "dependencies": { "@types/node": "*", @@ -4227,10 +4218,10 @@ "supports-color": "^8.0.0" }, "engines": { - "node": ">= 10.13.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, - "node_modules/jest-worker/node_modules/supports-color": { + "node_modules/jest-runtime/node_modules/supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", @@ -4245,67 +4236,292 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true + "node_modules/jest-runtime/node_modules/write-file-atomic": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.1.tgz", + "integrity": "sha512-nSKUxgAbyioruk6hU87QzVbY279oYT6uiwgDoujth2ju4mJ+TZau7SQBhtbTmUyuNYTuXnSyRn66FV0+eCgcrQ==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" + } }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "node_modules/jest-snapshot": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-28.1.3.tgz", + "integrity": "sha512-4lzMgtiNlc3DU/8lZfmqxN3AYD6GGLbl+72rdBpXvcV+whX7mDrREzkPdp2RnmfIiWBg1YbuFSkXduF2JcafJg==", + "dev": true, "dependencies": { - "argparse": "^2.0.1" + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^28.1.3", + "@jest/transform": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/babel__traverse": "^7.0.6", + "@types/prettier": "^2.1.5", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^28.1.3", + "graceful-fs": "^4.2.9", + "jest-diff": "^28.1.3", + "jest-get-type": "^28.0.2", + "jest-haste-map": "^28.1.3", + "jest-matcher-utils": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-util": "^28.1.3", + "natural-compare": "^1.4.0", + "pretty-format": "^28.1.3", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/@jest/transform": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-28.1.3.tgz", + "integrity": "sha512-u5dT5di+oFI6hfcLOHGTAfmUxFRrjK+vnaP0kkVow9Md/M7V/MxqQMOz/VV25UZO8pzeA9PjfTpOu6BDuwSPQA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^28.1.3", + "@jridgewell/trace-mapping": "^0.3.13", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^28.1.3", + "jest-regex-util": "^28.0.2", + "jest-util": "^28.1.3", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/diff-sequences": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.1.1.tgz", + "integrity": "sha512-FU0iFaH/E23a+a718l8Qa/19bF9p06kgE0KipMOMadwa3SjnaElKzPaUC0vnibs6/B/9ni97s61mcejk8W1fQw==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/jest-diff": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.1.3.tgz", + "integrity": "sha512-8RqP1B/OXzjjTWkqMX67iqgwBVJRgCyKD3L9nq+6ZqJMdvjE8RgHktqZ6jNrkdMT+dJuYNI3rhQpxaz7drJHfw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^28.1.1", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/jest-get-type": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", + "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/jest-haste-map": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-28.1.3.tgz", + "integrity": "sha512-3S+RQWDXccXDKSWnkHa/dPwt+2qwA8CJzR61w3FoYCvoo3Pn8tvGcysmMF0Bj0EX5RYvAI2EIvC57OmotfdtKA==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^28.0.2", + "jest-util": "^28.1.3", + "jest-worker": "^28.1.3", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-snapshot/node_modules/jest-regex-util": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", + "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/jest-worker": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.3.tgz", + "integrity": "sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" }, "bin": { - "js-yaml": "bin/js-yaml.js" + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, - "node_modules/jsdom": { - "version": "16.7.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", - "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", + "node_modules/jest-snapshot/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, "dependencies": { - "abab": "^2.0.5", - "acorn": "^8.2.4", - "acorn-globals": "^6.0.0", - "cssom": "^0.4.4", - "cssstyle": "^2.3.0", - "data-urls": "^2.0.0", - "decimal.js": "^10.2.1", - "domexception": "^2.0.1", - "escodegen": "^2.0.0", - "form-data": "^3.0.0", - "html-encoding-sniffer": "^2.0.1", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.0", - "parse5": "6.0.1", - "saxes": "^5.0.1", - "symbol-tree": "^3.2.4", - "tough-cookie": "^4.0.0", - "w3c-hr-time": "^1.0.2", - "w3c-xmlserializer": "^2.0.0", - "webidl-conversions": "^6.1.0", - "whatwg-encoding": "^1.0.5", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.5.0", - "ws": "^7.4.6", - "xml-name-validator": "^3.0.0" + "has-flag": "^4.0.0" }, "engines": { "node": ">=10" }, - "peerDependencies": { - "canvas": "^2.5.0" + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/jest-snapshot/node_modules/write-file-atomic": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.1.tgz", + "integrity": "sha512-nSKUxgAbyioruk6hU87QzVbY279oYT6uiwgDoujth2ju4mJ+TZau7SQBhtbTmUyuNYTuXnSyRn66FV0+eCgcrQ==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" + } + }, + "node_modules/jest-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", + "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-validate": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-28.1.3.tgz", + "integrity": "sha512-SZbOGBWEsaTxBGCOpsRWlXlvNkvTkY0XxRfh7zYmvd8uL5Qzyg0CHAXiXKROflh801quA6+/DsT4ODDthOC/OA==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^28.0.2", + "leven": "^3.1.0", + "pretty-format": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-validate/node_modules/jest-get-type": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", + "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-watcher": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-28.1.3.tgz", + "integrity": "sha512-t4qcqj9hze+jviFPUN3YAtAEeFnr/azITXQEMARf5cMwKY2SMBRnCQTXLixTl20OR6mLh9KLMrgVJgJISym+1g==", + "dev": true, + "dependencies": { + "@jest/test-result": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.10.2", + "jest-util": "^28.1.3", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dependencies": { + "argparse": "^2.0.1" }, - "peerDependenciesMeta": { - "canvas": { - "optional": true - } + "bin": { + "js-yaml": "bin/js-yaml.js" } }, "node_modules/jsesc": { @@ -4320,13 +4536,16 @@ "node": ">=4" } }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, "node_modules/json5": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", - "dependencies": { - "minimist": "^1.2.5" - }, + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", + "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", "bin": { "json5": "lib/cli.js" }, @@ -4352,24 +4571,17 @@ "node": ">=6" } }, - "node_modules/levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dev": true, - "dependencies": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/libphonenumber-js": { "version": "1.9.34", "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.9.34.tgz", "integrity": "sha512-gHTNU9xTtVgSp30IDX/57W4pETMXDIYXFfwEOJVXiYosiY7Hc7ogJwlBjOqlCcU04X0aA8DT57hdwUC1sJBJnA==" }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, "node_modules/locate-path": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", @@ -4382,12 +4594,6 @@ "node": ">=8" } }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, "node_modules/lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", @@ -4632,7 +4838,7 @@ "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, "node_modules/negotiator": { @@ -4679,15 +4885,6 @@ "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", "dev": true }, - "node_modules/node-modules-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", - "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/node-releases": { "version": "1.1.75", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.75.tgz", @@ -4734,12 +4931,6 @@ "node": ">=0.10.0" } }, - "node_modules/nwsapi": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", - "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", - "dev": true - }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -4791,23 +4982,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dev": true, - "dependencies": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/p-limit": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", @@ -4849,11 +5023,23 @@ "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" }, - "node_modules/parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/parseurl": { "version": "1.3.3", @@ -4996,13 +5182,10 @@ } }, "node_modules/pirates": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", - "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", + "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", "dev": true, - "dependencies": { - "node-modules-regexp": "^1.0.0" - }, "engines": { "node": ">= 6" } @@ -5080,15 +5263,6 @@ "node": ">=6" } }, - "node_modules/prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/prettier": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.6.2.tgz", @@ -5104,18 +5278,18 @@ } }, "node_modules/pretty-format": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.4.2.tgz", - "integrity": "sha512-p0wNtJ9oLuvgOQDEIZ9zQjZffK7KtyR6Si0jnXULIDwrlNF8Cuir3AZP0hHv0jmKuNN/edOnbMjnzd4uTcmWiw==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", + "integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==", "dev": true, "dependencies": { - "@jest/types": "^27.4.2", + "@jest/schemas": "^28.1.3", "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" + "react-is": "^18.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/pretty-format/node_modules/ansi-styles": { @@ -5160,12 +5334,6 @@ "node": ">= 0.10" } }, - "node_modules/psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", - "dev": true - }, "node_modules/pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", @@ -5175,15 +5343,6 @@ "once": "^1.3.1" } }, - "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/qs": { "version": "6.9.7", "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz", @@ -5232,9 +5391,9 @@ } }, "node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", "dev": true }, "node_modules/readable-stream": { @@ -5259,20 +5418,24 @@ "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "dev": true, "engines": { "node": ">=0.10.0" } }, "node_modules/resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", "dev": true, "dependencies": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -5333,18 +5496,6 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, - "node_modules/saxes": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", - "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", - "dev": true, - "dependencies": { - "xmlchars": "^2.2.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", @@ -5442,9 +5593,9 @@ } }, "node_modules/signal-exit": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.4.tgz", - "integrity": "sha512-rqYhcAnZ6d/vTPGghdrw7iumdcbXpsk1b8IG/rz+VWV51DM0p7XCtMoJ3qhPLIbp3tvyt3pKRbaaEMZYpHto8Q==" + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, "node_modules/simple-concat": { "version": "1.0.1", @@ -5509,9 +5660,9 @@ } }, "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", "dev": true, "dependencies": { "buffer-from": "^1.0.0", @@ -5782,11 +5933,17 @@ "node": ">=8" } }, - "node_modules/symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/tar": { "version": "6.1.11", @@ -5878,12 +6035,6 @@ "node": ">=8" } }, - "node_modules/throat": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.1.tgz", - "integrity": "sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w==", - "dev": true - }, "node_modules/timers-ext": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz", @@ -5920,70 +6071,46 @@ "node": ">=8.0" } }, - "node_modules/tough-cookie": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", - "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", - "dev": true, - "dependencies": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.1.2" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tr46": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", - "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", - "dev": true, - "dependencies": { - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/ts-jest": { - "version": "27.1.0", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-27.1.0.tgz", - "integrity": "sha512-ZouWlP03JMtzfNHg0ZeDrxAESYGmVhWyHtIl2/01kBbXaMbTr4Vhv6/GeMxUed6GFg/4ycMo+yU6Eo9gI16xTQ==", + "version": "28.0.7", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-28.0.7.tgz", + "integrity": "sha512-wWXCSmTwBVmdvWrOpYhal79bDpioDy4rTT+0vyUnE3ZzM7LOAAGG9NXwzkEL/a516rQEgnMmS/WKP9jBPCVJyA==", "dev": true, "dependencies": { "bs-logger": "0.x", - "esbuild": "~0.14.0", "fast-json-stable-stringify": "2.x", - "jest-util": "^27.0.0", - "json5": "2.x", + "jest-util": "^28.0.0", + "json5": "^2.2.1", "lodash.memoize": "4.x", "make-error": "1.x", "semver": "7.x", - "yargs-parser": "20.x" + "yargs-parser": "^21.0.1" }, "bin": { "ts-jest": "cli.js" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" }, "peerDependencies": { "@babel/core": ">=7.0.0-beta.0 <8", - "@types/jest": "^27.0.0", - "babel-jest": ">=27.0.0 <28", - "jest": "^27.0.0", - "typescript": ">=3.8 <5.0" + "@jest/types": "^28.0.0", + "babel-jest": "^28.0.0", + "jest": "^28.0.0", + "typescript": ">=4.3" }, "peerDependenciesMeta": { "@babel/core": { "optional": true }, - "@types/jest": { + "@jest/types": { "optional": true }, "babel-jest": { "optional": true + }, + "esbuild": { + "optional": true } } }, @@ -6104,18 +6231,6 @@ "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" }, - "node_modules/type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dev": true, - "dependencies": { - "prelude-ls": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/type-detect": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", @@ -6149,15 +6264,6 @@ "node": ">= 0.6" } }, - "node_modules/typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dev": true, - "dependencies": { - "is-typedarray": "^1.0.0" - } - }, "node_modules/typescript": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.3.tgz", @@ -6170,15 +6276,6 @@ "node": ">=4.2.0" } }, - "node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -6209,28 +6306,19 @@ } }, "node_modules/v8-to-istanbul": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.0.tgz", - "integrity": "sha512-/PRhfd8aTNp9Ggr62HPzXg2XasNFGy5PBt0Rp04du7/8GNNSgxFL6WBTkgMKSL9bFjH+8kKEG3f37FmxiTqUUA==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz", + "integrity": "sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==", "dev": true, "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0", - "source-map": "^0.7.3" + "convert-source-map": "^1.6.0" }, "engines": { "node": ">=10.12.0" } }, - "node_modules/v8-to-istanbul/node_modules/source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -6239,27 +6327,6 @@ "node": ">= 0.8" } }, - "node_modules/w3c-hr-time": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", - "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", - "dev": true, - "dependencies": { - "browser-process-hrtime": "^1.0.0" - } - }, - "node_modules/w3c-xmlserializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", - "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", - "dev": true, - "dependencies": { - "xml-name-validator": "^3.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/walker": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", @@ -6269,44 +6336,6 @@ "makeerror": "1.0.12" } }, - "node_modules/webidl-conversions": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", - "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", - "dev": true, - "engines": { - "node": ">=10.4" - } - }, - "node_modules/whatwg-encoding": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", - "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", - "dev": true, - "dependencies": { - "iconv-lite": "0.4.24" - } - }, - "node_modules/whatwg-mimetype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", - "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", - "dev": true - }, - "node_modules/whatwg-url": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", - "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", - "dev": true, - "dependencies": { - "lodash": "^4.7.0", - "tr46": "^2.1.0", - "webidl-conversions": "^6.1.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -6330,15 +6359,6 @@ "string-width": "^1.0.2 || 2" } }, - "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -6384,51 +6404,6 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, - "node_modules/write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "node_modules/ws": { - "version": "7.5.6", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.6.tgz", - "integrity": "sha512-6GLgCqo2cy2A2rjCNFlxQS6ZljG/coZfZXclldI8FB/1G3CCI36Zd8xy2HrFVACi8tfk5XrgLQEk+P0Tnz9UcA==", - "dev": true, - "engines": { - "node": ">=8.3.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/xml-name-validator": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", - "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", - "dev": true - }, - "node_modules/xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "dev": true - }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -6452,30 +6427,30 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "version": "17.5.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", + "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", "dev": true, "dependencies": { "cliui": "^7.0.2", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "string-width": "^4.2.0", + "string-width": "^4.2.3", "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" + "yargs-parser": "^21.0.0" }, "engines": { - "node": ">=10" + "node": ">=12" } }, "node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "version": "21.0.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.1.tgz", + "integrity": "sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==", "dev": true, "engines": { - "node": ">=10" + "node": ">=12" } }, "node_modules/yargs/node_modules/is-fullwidth-code-point": { @@ -6508,6 +6483,18 @@ "engines": { "node": ">=6" } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } }, "dependencies": { @@ -6682,9 +6669,9 @@ } }, "@babel/helper-plugin-utils": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz", - "integrity": "sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.9.tgz", + "integrity": "sha512-aBXPT3bmtLryXaoJLyYPXPlSD4p1ld9aYeR+sJNOZjJJGiOpb+fKfh3NkcCu7J54nUJwCERPBExCCpyCOHnu/w==", "dev": true }, "@babel/helper-replace-supers": { @@ -6924,12 +6911,12 @@ } }, "@babel/plugin-syntax-typescript": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.0.tgz", - "integrity": "sha512-Xv6mEXqVdaqCBfJFyeab0fH2DnUoMsDmhamxsSi4j8nLd4Vtw213WMJr55xxqipC/YVWyPY3K0blJncPYji+dQ==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.18.6.tgz", + "integrity": "sha512-mAWAuq4rvOepWCBid55JuRNvpTNf2UGVgoz4JV0fXEKolsVZDzsa4NqCef758WZJj/GDu0gVGItjKFiClTAmZA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/template": { @@ -7047,196 +7034,449 @@ "dev": true }, "@jest/console": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.4.2.tgz", - "integrity": "sha512-xknHThRsPB/To1FUbi6pCe43y58qFC03zfb6R7fDb/FfC7k2R3i1l+izRBJf8DI46KhYGRaF14Eo9A3qbBoixg==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-28.1.3.tgz", + "integrity": "sha512-QPAkP5EwKdK/bxIr6C1I4Vs0rm2nHiANzj/Z5X2JQkrZo6IqvC4ldZ9K95tF0HdidhA8Bo6egxSzUFPYKcEXLw==", "dev": true, "requires": { - "@jest/types": "^27.4.2", + "@jest/types": "^28.1.3", "@types/node": "*", "chalk": "^4.0.0", - "jest-message-util": "^27.4.2", - "jest-util": "^27.4.2", + "jest-message-util": "^28.1.3", + "jest-util": "^28.1.3", "slash": "^3.0.0" } }, "@jest/core": { - "version": "27.4.3", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.4.3.tgz", - "integrity": "sha512-V9ms3zSxUHxh1E/ZLAiXF7SLejsdFnjWTFizWotMOWvjho0lW5kSjZymhQSodNW0T0ZMQRiha7f8+NcFVm3hJQ==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-28.1.3.tgz", + "integrity": "sha512-CIKBrlaKOzA7YG19BEqCw3SLIsEwjZkeJzf5bdooVnW4bH5cktqe3JX+G2YV1aK5vP8N9na1IGWFzYaTp6k6NA==", "dev": true, "requires": { - "@jest/console": "^27.4.2", - "@jest/reporters": "^27.4.2", - "@jest/test-result": "^27.4.2", - "@jest/transform": "^27.4.2", - "@jest/types": "^27.4.2", + "@jest/console": "^28.1.3", + "@jest/reporters": "^28.1.3", + "@jest/test-result": "^28.1.3", + "@jest/transform": "^28.1.3", + "@jest/types": "^28.1.3", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", - "emittery": "^0.8.1", + "ci-info": "^3.2.0", "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "jest-changed-files": "^27.4.2", - "jest-config": "^27.4.3", - "jest-haste-map": "^27.4.2", - "jest-message-util": "^27.4.2", - "jest-regex-util": "^27.4.0", - "jest-resolve": "^27.4.2", - "jest-resolve-dependencies": "^27.4.2", - "jest-runner": "^27.4.3", - "jest-runtime": "^27.4.2", - "jest-snapshot": "^27.4.2", - "jest-util": "^27.4.2", - "jest-validate": "^27.4.2", - "jest-watcher": "^27.4.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^28.1.3", + "jest-config": "^28.1.3", + "jest-haste-map": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-regex-util": "^28.0.2", + "jest-resolve": "^28.1.3", + "jest-resolve-dependencies": "^28.1.3", + "jest-runner": "^28.1.3", + "jest-runtime": "^28.1.3", + "jest-snapshot": "^28.1.3", + "jest-util": "^28.1.3", + "jest-validate": "^28.1.3", + "jest-watcher": "^28.1.3", "micromatch": "^4.0.4", + "pretty-format": "^28.1.3", "rimraf": "^3.0.0", "slash": "^3.0.0", "strip-ansi": "^6.0.0" + }, + "dependencies": { + "@jest/transform": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-28.1.3.tgz", + "integrity": "sha512-u5dT5di+oFI6hfcLOHGTAfmUxFRrjK+vnaP0kkVow9Md/M7V/MxqQMOz/VV25UZO8pzeA9PjfTpOu6BDuwSPQA==", + "dev": true, + "requires": { + "@babel/core": "^7.11.6", + "@jest/types": "^28.1.3", + "@jridgewell/trace-mapping": "^0.3.13", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^28.1.3", + "jest-regex-util": "^28.0.2", + "jest-util": "^28.1.3", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.1" + } + }, + "jest-haste-map": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-28.1.3.tgz", + "integrity": "sha512-3S+RQWDXccXDKSWnkHa/dPwt+2qwA8CJzR61w3FoYCvoo3Pn8tvGcysmMF0Bj0EX5RYvAI2EIvC57OmotfdtKA==", + "dev": true, + "requires": { + "@jest/types": "^28.1.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "fsevents": "^2.3.2", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^28.0.2", + "jest-util": "^28.1.3", + "jest-worker": "^28.1.3", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + } + }, + "jest-regex-util": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", + "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==", + "dev": true + }, + "jest-worker": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.3.tgz", + "integrity": "sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==", + "dev": true, + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + } + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "write-file-atomic": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.1.tgz", + "integrity": "sha512-nSKUxgAbyioruk6hU87QzVbY279oYT6uiwgDoujth2ju4mJ+TZau7SQBhtbTmUyuNYTuXnSyRn66FV0+eCgcrQ==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + } + } } }, "@jest/environment": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.4.2.tgz", - "integrity": "sha512-uSljKxh/rGlHlmhyeG4ZoVK9hOec+EPBkwTHkHKQ2EqDu5K+MaG9uJZ8o1CbRsSdZqSuhXvJCYhBWsORPPg6qw==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-28.1.3.tgz", + "integrity": "sha512-1bf40cMFTEkKyEf585R9Iz1WayDjHoHqvts0XFYEqyKM3cFWDpeMoqKKTAF9LSYQModPUlh8FKptoM2YcMWAXA==", "dev": true, "requires": { - "@jest/fake-timers": "^27.4.2", - "@jest/types": "^27.4.2", + "@jest/fake-timers": "^28.1.3", + "@jest/types": "^28.1.3", "@types/node": "*", - "jest-mock": "^27.4.2" + "jest-mock": "^28.1.3" + } + }, + "@jest/expect": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-28.1.3.tgz", + "integrity": "sha512-lzc8CpUbSoE4dqT0U+g1qODQjBRHPpCPXissXD4mS9+sWQdmmpeJ9zSH1rS1HEkrsMN0fb7nKrJ9giAR1d3wBw==", + "dev": true, + "requires": { + "expect": "^28.1.3", + "jest-snapshot": "^28.1.3" + } + }, + "@jest/expect-utils": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-28.1.3.tgz", + "integrity": "sha512-wvbi9LUrHJLn3NlDW6wF2hvIMtd4JUl2QNVrjq+IBSHirgfrR3o9RnVtxzdEGO2n9JyIWwHnLfby5KzqBGg2YA==", + "dev": true, + "requires": { + "jest-get-type": "^28.0.2" + }, + "dependencies": { + "jest-get-type": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", + "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "dev": true + } } }, "@jest/fake-timers": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.4.2.tgz", - "integrity": "sha512-f/Xpzn5YQk5adtqBgvw1V6bF8Nx3hY0OIRRpCvWcfPl0EAjdqWPdhH3t/3XpiWZqtjIEHDyMKP9ajpva1l4Zmg==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-28.1.3.tgz", + "integrity": "sha512-D/wOkL2POHv52h+ok5Oj/1gOG9HSywdoPtFsRCUmlCILXNn5eIWmcnd3DIiWlJnpGvQtmajqBP95Ei0EimxfLw==", "dev": true, "requires": { - "@jest/types": "^27.4.2", - "@sinonjs/fake-timers": "^8.0.1", + "@jest/types": "^28.1.3", + "@sinonjs/fake-timers": "^9.1.2", "@types/node": "*", - "jest-message-util": "^27.4.2", - "jest-mock": "^27.4.2", - "jest-util": "^27.4.2" + "jest-message-util": "^28.1.3", + "jest-mock": "^28.1.3", + "jest-util": "^28.1.3" } }, "@jest/globals": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.4.2.tgz", - "integrity": "sha512-KkfaHEttlGpXYAQTZHgrESiEPx2q/DKAFLGLFda1uGVrqc17snd3YVPhOxlXOHIzVPs+lQ/SDB2EIvxyGzb3Ew==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-28.1.3.tgz", + "integrity": "sha512-XFU4P4phyryCXu1pbcqMO0GSQcYe1IsalYCDzRNyhetyeyxMcIxa11qPNDpVNLeretItNqEmYYQn1UYz/5x1NA==", "dev": true, "requires": { - "@jest/environment": "^27.4.2", - "@jest/types": "^27.4.2", - "expect": "^27.4.2" + "@jest/environment": "^28.1.3", + "@jest/expect": "^28.1.3", + "@jest/types": "^28.1.3" } }, "@jest/reporters": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.4.2.tgz", - "integrity": "sha512-sp4aqmdBJtjKetEakzDPcZggPcVIF6w9QLkYBbaWDV6e/SIsHnF1S4KtIH91eEc2fp7ep6V/e1xvdfEoho1d2w==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-28.1.3.tgz", + "integrity": "sha512-JuAy7wkxQZVNU/V6g9xKzCGC5LVXx9FDcABKsSXp5MiKPEE2144a/vXTEDoyzjUpZKfVwp08Wqg5A4WfTMAzjg==", "dev": true, "requires": { "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^27.4.2", - "@jest/test-result": "^27.4.2", - "@jest/transform": "^27.4.2", - "@jest/types": "^27.4.2", + "@jest/console": "^28.1.3", + "@jest/test-result": "^28.1.3", + "@jest/transform": "^28.1.3", + "@jest/types": "^28.1.3", + "@jridgewell/trace-mapping": "^0.3.13", "@types/node": "*", "chalk": "^4.0.0", "collect-v8-coverage": "^1.0.0", "exit": "^0.1.2", - "glob": "^7.1.2", - "graceful-fs": "^4.2.4", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^4.0.3", + "istanbul-lib-instrument": "^5.1.0", "istanbul-lib-report": "^3.0.0", "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.0.2", - "jest-haste-map": "^27.4.2", - "jest-resolve": "^27.4.2", - "jest-util": "^27.4.2", - "jest-worker": "^27.4.2", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^28.1.3", + "jest-util": "^28.1.3", + "jest-worker": "^28.1.3", "slash": "^3.0.0", - "source-map": "^0.6.0", "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", "terminal-link": "^2.0.0", - "v8-to-istanbul": "^8.1.0" + "v8-to-istanbul": "^9.0.1" + }, + "dependencies": { + "@jest/transform": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-28.1.3.tgz", + "integrity": "sha512-u5dT5di+oFI6hfcLOHGTAfmUxFRrjK+vnaP0kkVow9Md/M7V/MxqQMOz/VV25UZO8pzeA9PjfTpOu6BDuwSPQA==", + "dev": true, + "requires": { + "@babel/core": "^7.11.6", + "@jest/types": "^28.1.3", + "@jridgewell/trace-mapping": "^0.3.13", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^28.1.3", + "jest-regex-util": "^28.0.2", + "jest-util": "^28.1.3", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.1" + } + }, + "jest-haste-map": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-28.1.3.tgz", + "integrity": "sha512-3S+RQWDXccXDKSWnkHa/dPwt+2qwA8CJzR61w3FoYCvoo3Pn8tvGcysmMF0Bj0EX5RYvAI2EIvC57OmotfdtKA==", + "dev": true, + "requires": { + "@jest/types": "^28.1.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "fsevents": "^2.3.2", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^28.0.2", + "jest-util": "^28.1.3", + "jest-worker": "^28.1.3", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + } + }, + "jest-regex-util": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", + "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==", + "dev": true + }, + "jest-worker": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.3.tgz", + "integrity": "sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==", + "dev": true, + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + } + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "write-file-atomic": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.1.tgz", + "integrity": "sha512-nSKUxgAbyioruk6hU87QzVbY279oYT6uiwgDoujth2ju4mJ+TZau7SQBhtbTmUyuNYTuXnSyRn66FV0+eCgcrQ==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + } + } + } + }, + "@jest/schemas": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.1.3.tgz", + "integrity": "sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==", + "dev": true, + "requires": { + "@sinclair/typebox": "^0.24.1" } }, "@jest/source-map": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.4.0.tgz", - "integrity": "sha512-Ntjx9jzP26Bvhbm93z/AKcPRj/9wrkI88/gK60glXDx1q+IeI0rf7Lw2c89Ch6ofonB0On/iRDreQuQ6te9pgQ==", + "version": "28.1.2", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-28.1.2.tgz", + "integrity": "sha512-cV8Lx3BeStJb8ipPHnqVw/IM2VCMWO3crWZzYodSIkxXnRcXJipCdx1JCK0K5MsJJouZQTH73mzf4vgxRaH9ww==", "dev": true, "requires": { + "@jridgewell/trace-mapping": "^0.3.13", "callsites": "^3.0.0", - "graceful-fs": "^4.2.4", - "source-map": "^0.6.0" + "graceful-fs": "^4.2.9" } }, "@jest/test-result": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.4.2.tgz", - "integrity": "sha512-kr+bCrra9jfTgxHXHa2UwoQjxvQk3Am6QbpAiJ5x/50LW8llOYrxILkqY0lZRW/hu8FXesnudbql263+EW9iNA==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-28.1.3.tgz", + "integrity": "sha512-kZAkxnSE+FqE8YjW8gNuoVkkC9I7S1qmenl8sGcDOLropASP+BkcGKwhXoyqQuGOGeYY0y/ixjrd/iERpEXHNg==", "dev": true, "requires": { - "@jest/console": "^27.4.2", - "@jest/types": "^27.4.2", + "@jest/console": "^28.1.3", + "@jest/types": "^28.1.3", "@types/istanbul-lib-coverage": "^2.0.0", "collect-v8-coverage": "^1.0.0" } }, "@jest/test-sequencer": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.4.2.tgz", - "integrity": "sha512-HmHp5mlh9f9GyNej5yCS1JZIFfUGnP9+jEOH5zoq5EmsuZeYD+dGULqyvGDPtuzzbyAFJ6R4+z4SS0VvnFwwGQ==", - "dev": true, - "requires": { - "@jest/test-result": "^27.4.2", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.4.2", - "jest-runtime": "^27.4.2" - } - }, - "@jest/transform": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.4.2.tgz", - "integrity": "sha512-RTKcPZllfcmLfnlxBya7aypofhdz05+E6QITe55Ex0rxyerkgjmmpMlvVn11V0cP719Ps6WcDYCnDzxnnJUwKg==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-28.1.3.tgz", + "integrity": "sha512-NIMPEqqa59MWnDi1kvXXpYbqsfQmSJsIbnd85mdVGkiDfQ9WQQTXOLsvISUfonmnBT+w85WEgneCigEEdHDFxw==", "dev": true, "requires": { - "@babel/core": "^7.1.0", - "@jest/types": "^27.4.2", - "babel-plugin-istanbul": "^6.0.0", - "chalk": "^4.0.0", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.0.0", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.4.2", - "jest-regex-util": "^27.4.0", - "jest-util": "^27.4.2", - "micromatch": "^4.0.4", - "pirates": "^4.0.1", - "slash": "^3.0.0", - "source-map": "^0.6.1", - "write-file-atomic": "^3.0.0" + "@jest/test-result": "^28.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^28.1.3", + "slash": "^3.0.0" + }, + "dependencies": { + "jest-haste-map": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-28.1.3.tgz", + "integrity": "sha512-3S+RQWDXccXDKSWnkHa/dPwt+2qwA8CJzR61w3FoYCvoo3Pn8tvGcysmMF0Bj0EX5RYvAI2EIvC57OmotfdtKA==", + "dev": true, + "requires": { + "@jest/types": "^28.1.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "fsevents": "^2.3.2", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^28.0.2", + "jest-util": "^28.1.3", + "jest-worker": "^28.1.3", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + } + }, + "jest-regex-util": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", + "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==", + "dev": true + }, + "jest-worker": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.3.tgz", + "integrity": "sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==", + "dev": true, + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + } + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", + "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", "dev": true, "requires": { + "@jest/schemas": "^28.1.3", "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^3.0.0", "@types/node": "*", - "@types/yargs": "^16.0.0", + "@types/yargs": "^17.0.8", "chalk": "^4.0.0" } }, + "@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.14", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz", + "integrity": "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "@sinclair/typebox": { + "version": "0.24.22", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.22.tgz", + "integrity": "sha512-JsBe3cOFpNZ6yjBYnXKhcENWy5qZE3PQZwExQ5ksA/h8qp4bwwxFmy07A6bC2R6qv6+RF3SfrbQTskTwYNTXUQ==", + "dev": true + }, "@sinonjs/commons": { "version": "1.8.3", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", @@ -7247,18 +7487,18 @@ } }, "@sinonjs/fake-timers": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz", - "integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==", + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", + "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", "dev": true, "requires": { "@sinonjs/commons": "^1.7.0" } }, "@snowtop/ent": { - "version": "0.1.0-alpha51", - "resolved": "https://registry.npmjs.org/@snowtop/ent/-/ent-0.1.0-alpha51.tgz", - "integrity": "sha512-C5P5HK/lEnNZqQXExsXDj1Bth26jAFVlOsANxC/9O4aszVCgyZeMFe/K9Cm2ZffGeCa+h4AuJM66JF+wzZDtgw==", + "version": "0.1.0-alpha55", + "resolved": "https://registry.npmjs.org/@snowtop/ent/-/ent-0.1.0-alpha55.tgz", + "integrity": "sha512-L0tI3r2YARhfiOkUMRCzTBISuoZU4Xji7/+Z/huLxLKMDN/KV2UL9OFNgcxns7JFNKaIRF70ciRK2QjuEgNveQ==", "requires": { "@types/node": "^15.0.2", "camel-case": "^4.1.2", @@ -7303,19 +7543,13 @@ } }, "@snowtop/ent-soft-delete": { - "version": "0.1.0-alpha1", - "resolved": "https://registry.npmjs.org/@snowtop/ent-soft-delete/-/ent-soft-delete-0.1.0-alpha1.tgz", - "integrity": "sha512-f6JngJw16HRgZ6G0chDqOOJ6vOkulbbHWz5IpOA87HbptGe2SjpBuuNiyEMYOe+Krtr1lUjw/knbIw2aEJTFlg==", + "version": "0.1.0-alpha3", + "resolved": "https://registry.npmjs.org/@snowtop/ent-soft-delete/-/ent-soft-delete-0.1.0-alpha3.tgz", + "integrity": "sha512-CnBb3iVcsXT8CjgE5ukH5rSDqX9+pymYX+mixA1SlvCDoaC1y6TzC23eaN1Q0ndrnPT7VKuFF40wqzLMnBVmjw==", "requires": { "@types/express": "^4.17.13" } }, - "@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", - "dev": true - }, "@tsconfig/node10": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz", @@ -7455,13 +7689,13 @@ } }, "@types/jest": { - "version": "27.0.1", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.0.1.tgz", - "integrity": "sha512-HTLpVXHrY69556ozYkcq47TtQJXpcWAWfkoqz+ZGz2JnmZhzlRjprCIyFnetSy8gpDWwTTGBcRVv1J1I1vBrHw==", + "version": "28.1.6", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-28.1.6.tgz", + "integrity": "sha512-0RbGAFMfcBJKOmqRazM8L98uokwuwD5F8rHrv/ZMbrZBwVOWZUyPG6VFNscjYr/vjM3Vu4fRrCPbOs42AfemaQ==", "dev": true, "requires": { - "jest-diff": "^27.0.0", - "pretty-format": "^27.0.0" + "jest-matcher-utils": "^28.0.0", + "pretty-format": "^28.0.0" } }, "@types/jest-expect-message": { @@ -7499,9 +7733,9 @@ } }, "@types/prettier": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.2.tgz", - "integrity": "sha512-ekoj4qOQYp7CvjX8ZDBgN86w3MqQhLE1hczEJbEIjgFEumDy+na/4AJAbLXfgEWFNB2pKadM5rPFtuSGMWK7xA==", + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.6.4.tgz", + "integrity": "sha512-fOwvpvQYStpb/zHMx0Cauwywu9yLDmzWiiQBC7gJyq5tYLUXFZvDG7VK1B7WBxxjBJNKFOZ0zLoOQn8vmATbhw==", "dev": true }, "@types/qs": { @@ -7555,24 +7789,18 @@ "dev": true }, "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "version": "17.0.10", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", + "integrity": "sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA==", "dev": true, "requires": { "@types/yargs-parser": "*" } }, "@types/yargs-parser": { - "version": "20.2.1", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.1.tgz", - "integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==", - "dev": true - }, - "abab": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", - "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==", + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", "dev": true }, "accepts": { @@ -7589,56 +7817,6 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.5.0.tgz", "integrity": "sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==" }, - "acorn-globals": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", - "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", - "dev": true, - "requires": { - "acorn": "^7.1.1", - "acorn-walk": "^7.1.1" - }, - "dependencies": { - "acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true - } - } - }, - "acorn-walk": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", - "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", - "dev": true - }, - "agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "requires": { - "debug": "4" - }, - "dependencies": { - "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } - }, "ansi-escapes": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", @@ -7708,47 +7886,19 @@ "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", "dev": true }, - "babel-jest": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.4.2.tgz", - "integrity": "sha512-MADrjb3KBO2eyZCAc6QaJg6RT5u+6oEdDyHO5HEalnpwQ6LrhTsQF2Kj1Wnz2t6UPXIXPk18dSXXOT0wF5yTxA==", - "dev": true, - "requires": { - "@jest/transform": "^27.4.2", - "@jest/types": "^27.4.2", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.0.0", - "babel-preset-jest": "^27.4.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "slash": "^3.0.0" - } - }, "babel-plugin-istanbul": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz", - "integrity": "sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.0.0", "@istanbuljs/load-nyc-config": "^1.0.0", "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^4.0.0", + "istanbul-lib-instrument": "^5.0.4", "test-exclude": "^6.0.0" } }, - "babel-plugin-jest-hoist": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.4.0.tgz", - "integrity": "sha512-Jcu7qS4OX5kTWBc45Hz7BMmgXuJqRnhatqpUhnzGC3OBYpOmf2tv6jFNwZpwM7wU7MUuv2r9IPS/ZlYOuburVw==", - "dev": true, - "requires": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.0.0", - "@types/babel__traverse": "^7.0.6" - } - }, "babel-preset-current-node-syntax": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", @@ -7769,16 +7919,6 @@ "@babel/plugin-syntax-top-level-await": "^7.8.3" } }, - "babel-preset-jest": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.4.0.tgz", - "integrity": "sha512-NK4jGYpnBvNxcGo7/ZpZJr51jCGT+3bwwpVIDY2oNfTxJJldRtB4VAcYdgp1loDE50ODuTu+yBjpMAswv5tlpg==", - "dev": true, - "requires": { - "babel-plugin-jest-hoist": "^27.4.0", - "babel-preset-current-node-syntax": "^1.0.0" - } - }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -7864,12 +8004,6 @@ "fill-range": "^7.0.1" } }, - "browser-process-hrtime": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", - "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", - "dev": true - }, "browserslist": { "version": "4.17.0", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.0.tgz", @@ -8029,7 +8163,7 @@ "co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", "dev": true }, "code-point-at": { @@ -8155,29 +8289,6 @@ "which": "^2.0.1" } }, - "cssom": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", - "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", - "dev": true - }, - "cssstyle": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", - "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", - "dev": true, - "requires": { - "cssom": "~0.3.6" - }, - "dependencies": { - "cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", - "dev": true - } - } - }, "d": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", @@ -8187,17 +8298,6 @@ "type": "^1.0.1" } }, - "data-urls": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", - "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", - "dev": true, - "requires": { - "abab": "^2.0.3", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.0.0" - } - }, "dataloader": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/dataloader/-/dataloader-2.1.0.tgz", @@ -8211,12 +8311,6 @@ "ms": "2.0.0" } }, - "decimal.js": { - "version": "10.3.1", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz", - "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==", - "dev": true - }, "decompress-response": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", @@ -8228,7 +8322,7 @@ "dedent": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", + "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", "dev": true }, "deep-extend": { @@ -8236,12 +8330,6 @@ "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" }, - "deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, "deepmerge": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", @@ -8285,29 +8373,6 @@ "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==" }, - "diff-sequences": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.4.0.tgz", - "integrity": "sha512-YqiQzkrsmHMH5uuh8OdQFU9/ZpADnwzml8z0O5HvRNda+5UZsaX/xN+AAxfR2hWq1Y7HZnAzO9J5lJXOuDz2Ww==", - "dev": true - }, - "domexception": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", - "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", - "dev": true, - "requires": { - "webidl-conversions": "^5.0.0" - }, - "dependencies": { - "webidl-conversions": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", - "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", - "dev": true - } - } - }, "dot-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", @@ -8329,9 +8394,9 @@ "dev": true }, "emittery": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", - "integrity": "sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==", + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.10.2.tgz", + "integrity": "sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw==", "dev": true }, "emoji-regex": { @@ -8353,189 +8418,54 @@ "once": "^1.4.0" } }, - "es5-ext": { - "version": "0.10.61", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.61.tgz", - "integrity": "sha512-yFhIqQAzu2Ca2I4SE2Au3rxVfmohU9Y7wqGR+s7+H7krk26NXhIRAZDgqd6xqjCEFUomDEA3/Bo/7fKmIkW1kA==", - "requires": { - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.3", - "next-tick": "^1.1.0" - } - }, - "es6-iterator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", - "requires": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" - } - }, - "es6-symbol": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", - "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", - "requires": { - "d": "^1.0.1", - "ext": "^1.1.2" - } - }, - "es6-weak-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", - "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, "requires": { - "d": "1", - "es5-ext": "^0.10.46", - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.1" + "is-arrayish": "^0.2.1" } }, - "esbuild": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.2.tgz", - "integrity": "sha512-l076A6o/PIgcyM24s0dWmDI/b8RQf41uWoJu9I0M71CtW/YSw5T5NUeXxs5lo2tFQD+O4CW4nBHJXx3OY5NpXg==", - "dev": true, - "requires": { - "esbuild-android-arm64": "0.14.2", - "esbuild-darwin-64": "0.14.2", - "esbuild-darwin-arm64": "0.14.2", - "esbuild-freebsd-64": "0.14.2", - "esbuild-freebsd-arm64": "0.14.2", - "esbuild-linux-32": "0.14.2", - "esbuild-linux-64": "0.14.2", - "esbuild-linux-arm": "0.14.2", - "esbuild-linux-arm64": "0.14.2", - "esbuild-linux-mips64le": "0.14.2", - "esbuild-linux-ppc64le": "0.14.2", - "esbuild-netbsd-64": "0.14.2", - "esbuild-openbsd-64": "0.14.2", - "esbuild-sunos-64": "0.14.2", - "esbuild-windows-32": "0.14.2", - "esbuild-windows-64": "0.14.2", - "esbuild-windows-arm64": "0.14.2" - } - }, - "esbuild-android-arm64": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.2.tgz", - "integrity": "sha512-hEixaKMN3XXCkoe+0WcexO4CcBVU5DCSUT+7P8JZiWZCbAjSkc9b6Yz2X5DSfQmRCtI/cQRU6TfMYrMQ5NBfdw==", - "dev": true, - "optional": true - }, - "esbuild-darwin-64": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.2.tgz", - "integrity": "sha512-Uq8t0cbJQkxkQdbUfOl2wZqZ/AtLZjvJulR1HHnc96UgyzG9YlCLSDMiqjM+NANEy7/zzvwKJsy3iNC9wwqLJA==", - "dev": true, - "optional": true - }, - "esbuild-darwin-arm64": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.2.tgz", - "integrity": "sha512-619MSa17sr7YCIrUj88KzQu2ESA4jKYtIYfLU/smX6qNgxQt3Y/gzM4s6sgJ4fPQzirvmXgcHv1ZNQAs/Xh48A==", - "dev": true, - "optional": true - }, - "esbuild-freebsd-64": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.2.tgz", - "integrity": "sha512-aP6FE/ZsChZpUV6F3HE3x1Pz0paoYXycJ7oLt06g0G9dhJKknPawXCqQg/WMyD+ldCEZfo7F1kavenPdIT/SGQ==", - "dev": true, - "optional": true - }, - "esbuild-freebsd-arm64": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.2.tgz", - "integrity": "sha512-LSm98WTb1QIhyS83+Po0KTpZNdd2XpVpI9ua5rLWqKWbKeNRFwOsjeiuwBaRNc+O32s9oC2ZMefETxHBV6VNkQ==", - "dev": true, - "optional": true - }, - "esbuild-linux-32": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.2.tgz", - "integrity": "sha512-8VxnNEyeUbiGflTKcuVc5JEPTqXfsx2O6ABwUbfS1Hp26lYPRPC7pKQK5Dxa0MBejGc50jy7YZae3EGQUQ8EkQ==", - "dev": true, - "optional": true - }, - "esbuild-linux-64": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.2.tgz", - "integrity": "sha512-4bzMS2dNxOJoFIiHId4w+tqQzdnsch71JJV1qZnbnErSFWcR9lRgpSqWnTTFtv6XM+MvltRzSXC5wQ7AEBY6Hg==", - "dev": true, - "optional": true - }, - "esbuild-linux-arm": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.2.tgz", - "integrity": "sha512-PaylahvMHhH8YMfJPMKEqi64qA0Su+d4FNfHKvlKes/2dUe4QxgbwXT9oLVgy8iJdcFMrO7By4R8fS8S0p8aVQ==", - "dev": true, - "optional": true - }, - "esbuild-linux-arm64": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.2.tgz", - "integrity": "sha512-RlIVp0RwJrdtasDF1vTFueLYZ8WuFzxoQ1OoRFZOTyJHCGCNgh7xJIC34gd7B7+RT0CzLBB4LcM5n0LS+hIoww==", - "dev": true, - "optional": true - }, - "esbuild-linux-mips64le": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.2.tgz", - "integrity": "sha512-Fdwrq2roFnO5oetIiUQQueZ3+5soCxBSJswg3MvYaXDomj47BN6oAWMZgLrFh1oVrtWrxSDLCJBenYdbm2s+qQ==", - "dev": true, - "optional": true - }, - "esbuild-linux-ppc64le": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.2.tgz", - "integrity": "sha512-vxptskw8JfCDD9QqpRO0XnsM1osuWeRjPaXX1TwdveLogYsbdFtcuiuK/4FxGiNMUr1ojtnCS2rMPbY8puc5NA==", - "dev": true, - "optional": true - }, - "esbuild-netbsd-64": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.2.tgz", - "integrity": "sha512-I8+LzYK5iSNpspS9eCV9sW67Rj8FgMHimGri4mKiGAmN0pNfx+hFX146rYtzGtewuxKtTsPywWteHx+hPRLDsw==", - "dev": true, - "optional": true - }, - "esbuild-openbsd-64": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.2.tgz", - "integrity": "sha512-120HgMe9elidWUvM2E6mMf0csrGwx8sYDqUIJugyMy1oHm+/nT08bTAVXuwYG/rkMIqsEO9AlMxuYnwR6En/3Q==", - "dev": true, - "optional": true - }, - "esbuild-sunos-64": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.2.tgz", - "integrity": "sha512-Q3xcf9Uyfra9UuCFxoLixVvdigo0daZaKJ97TL2KNA4bxRUPK18wwGUk3AxvgDQZpRmg82w9PnkaNYo7a+24ow==", - "dev": true, - "optional": true + "es5-ext": { + "version": "0.10.61", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.61.tgz", + "integrity": "sha512-yFhIqQAzu2Ca2I4SE2Au3rxVfmohU9Y7wqGR+s7+H7krk26NXhIRAZDgqd6xqjCEFUomDEA3/Bo/7fKmIkW1kA==", + "requires": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "next-tick": "^1.1.0" + } }, - "esbuild-windows-32": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.2.tgz", - "integrity": "sha512-TW7O49tPsrq+N1sW8mb3m24j/iDGa4xzAZH4wHWwoIzgtZAYPKC0hpIhufRRG/LA30bdMChO9pjJZ5mtcybtBQ==", - "dev": true, - "optional": true + "es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", + "requires": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } }, - "esbuild-windows-64": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.2.tgz", - "integrity": "sha512-Rym6ViMNmi1E2QuQMWy0AFAfdY0wGwZD73BnzlsQBX5hZBuy/L+Speh7ucUZ16gwsrMM9v86icZUDrSN/lNBKg==", - "dev": true, - "optional": true + "es6-symbol": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", + "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "requires": { + "d": "^1.0.1", + "ext": "^1.1.2" + } }, - "esbuild-windows-arm64": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.2.tgz", - "integrity": "sha512-ZrLbhr0vX5Em/P1faMnHucjVVWPS+m3tktAtz93WkMZLmbRJevhiW1y4CbulBd2z0MEdXZ6emDa1zFHq5O5bSA==", - "dev": true, - "optional": true + "es6-weak-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", + "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", + "requires": { + "d": "1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.1" + } }, "escalade": { "version": "3.1.1", @@ -8554,37 +8484,12 @@ "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", "dev": true }, - "escodegen": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", - "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", - "dev": true, - "requires": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.6.1" - } - }, "esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true }, - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, "etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", @@ -8619,7 +8524,7 @@ "exit": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", "dev": true }, "expand-template": { @@ -8628,23 +8533,22 @@ "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==" }, "expect": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/expect/-/expect-27.4.2.tgz", - "integrity": "sha512-BjAXIDC6ZOW+WBFNg96J22D27Nq5ohn+oGcuP2rtOtcjuxNoV9McpQ60PcQWhdFOSBIQdR72e+4HdnbZTFSTyg==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/expect/-/expect-28.1.3.tgz", + "integrity": "sha512-eEh0xn8HlsuOBxFgIss+2mX85VAS4Qy3OSkjV7rlBWljtA4oWH37glVGyOZSZvErDT/yBywZdPGwCXuTvSG85g==", "dev": true, "requires": { - "@jest/types": "^27.4.2", - "ansi-styles": "^5.0.0", - "jest-get-type": "^27.4.0", - "jest-matcher-utils": "^27.4.2", - "jest-message-util": "^27.4.2", - "jest-regex-util": "^27.4.0" + "@jest/expect-utils": "^28.1.3", + "jest-get-type": "^28.0.2", + "jest-matcher-utils": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-util": "^28.1.3" }, "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "jest-get-type": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", + "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", "dev": true } } @@ -8714,12 +8618,6 @@ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "dev": true }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, "fast-safe-stringify": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", @@ -8921,9 +8819,9 @@ "dev": true }, "graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", "dev": true }, "graph-data-structure": { @@ -8968,15 +8866,6 @@ "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" }, - "html-encoding-sniffer": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", - "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", - "dev": true, - "requires": { - "whatwg-encoding": "^1.0.5" - } - }, "html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", @@ -9002,61 +8891,6 @@ } } }, - "http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", - "dev": true, - "requires": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" - }, - "dependencies": { - "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } - }, - "https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", - "dev": true, - "requires": { - "agent-base": "6", - "debug": "4" - }, - "dependencies": { - "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } - }, "human-signals": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", @@ -9077,9 +8911,9 @@ "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" }, "import-local": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.3.tgz", - "integrity": "sha512-bE9iaUY3CXH8Cwfan/abDKAxe1KGT9kyGsBPqf6DMK/z0a2OzAsrukeYNgIH6cH5Xr452jb1TUL8rSfCLjZ9uA==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", "dev": true, "requires": { "pkg-dir": "^4.2.0", @@ -9116,10 +8950,16 @@ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, "is-core-module": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", - "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", + "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", "dev": true, "requires": { "has": "^1.0.3" @@ -9145,12 +8985,6 @@ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, - "is-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "dev": true - }, "is-promise": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", @@ -9162,12 +8996,6 @@ "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -9176,24 +9004,25 @@ "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, "istanbul-lib-coverage": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", - "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", "dev": true }, "istanbul-lib-instrument": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", - "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz", + "integrity": "sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A==", "dev": true, "requires": { - "@babel/core": "^7.7.5", + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-coverage": "^3.2.0", "semver": "^6.3.0" } }, @@ -9220,9 +9049,9 @@ }, "dependencies": { "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "requires": { "ms": "2.1.2" @@ -9237,9 +9066,9 @@ } }, "istanbul-reports": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.1.tgz", - "integrity": "sha512-q1kvhAXWSsXfMjCdNHNPKZZv94OlspKnoGv+R9RGbnqOOQ0VbNfLFgQDVgi7hHenKsndGq3/o0OBdzDXthWcNw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", + "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", "dev": true, "requires": { "html-escaper": "^2.0.0", @@ -9247,102 +9076,254 @@ } }, "jest": { - "version": "27.4.3", - "resolved": "https://registry.npmjs.org/jest/-/jest-27.4.3.tgz", - "integrity": "sha512-jwsfVABBzuN3Atm+6h6vIEpTs9+VApODLt4dk2qv1WMOpb1weI1IIZfuwpMiWZ62qvWj78MvdvMHIYdUfqrFaA==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest/-/jest-28.1.3.tgz", + "integrity": "sha512-N4GT5on8UkZgH0O5LUavMRV1EDEhNTL0KEfRmDIeZHSV7p2XgLoY9t9VDUgL6o+yfdgYHVxuz81G8oB9VG5uyA==", "dev": true, "requires": { - "@jest/core": "^27.4.3", + "@jest/core": "^28.1.3", + "@jest/types": "^28.1.3", "import-local": "^3.0.2", - "jest-cli": "^27.4.3" + "jest-cli": "^28.1.3" } }, "jest-changed-files": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.4.2.tgz", - "integrity": "sha512-/9x8MjekuzUQoPjDHbBiXbNEBauhrPU2ct7m8TfCg69ywt1y/N+yYwGh3gCpnqUS3klYWDU/lSNgv+JhoD2k1A==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-28.1.3.tgz", + "integrity": "sha512-esaOfUWJXk2nfZt9SPyC8gA1kNfdKLkQWyzsMlqq8msYSlNKfmZxfRgZn4Cd4MGVUF+7v6dBs0d5TOAKa7iIiA==", "dev": true, "requires": { - "@jest/types": "^27.4.2", "execa": "^5.0.0", - "throat": "^6.0.1" + "p-limit": "^3.1.0" + }, + "dependencies": { + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + } } }, "jest-circus": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.4.2.tgz", - "integrity": "sha512-2ePUSru1BGMyzxsMvRfu+tNb+PW60rUyMLJBfw1Nrh5zC8RoTPfF+zbE0JToU31a6ZVe4nnrNKWYRzlghAbL0A==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-28.1.3.tgz", + "integrity": "sha512-cZ+eS5zc79MBwt+IhQhiEp0OeBddpc1n8MBo1nMB8A7oPMKEO+Sre+wHaLJexQUj9Ya/8NOBY0RESUgYjB6fow==", "dev": true, "requires": { - "@jest/environment": "^27.4.2", - "@jest/test-result": "^27.4.2", - "@jest/types": "^27.4.2", + "@jest/environment": "^28.1.3", + "@jest/expect": "^28.1.3", + "@jest/test-result": "^28.1.3", + "@jest/types": "^28.1.3", "@types/node": "*", "chalk": "^4.0.0", "co": "^4.6.0", "dedent": "^0.7.0", - "expect": "^27.4.2", "is-generator-fn": "^2.0.0", - "jest-each": "^27.4.2", - "jest-matcher-utils": "^27.4.2", - "jest-message-util": "^27.4.2", - "jest-runtime": "^27.4.2", - "jest-snapshot": "^27.4.2", - "jest-util": "^27.4.2", - "pretty-format": "^27.4.2", + "jest-each": "^28.1.3", + "jest-matcher-utils": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-runtime": "^28.1.3", + "jest-snapshot": "^28.1.3", + "jest-util": "^28.1.3", + "p-limit": "^3.1.0", + "pretty-format": "^28.1.3", "slash": "^3.0.0", - "stack-utils": "^2.0.3", - "throat": "^6.0.1" + "stack-utils": "^2.0.3" + }, + "dependencies": { + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + } } }, "jest-cli": { - "version": "27.4.3", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.4.3.tgz", - "integrity": "sha512-zZSJBXNC/i8UnJPwcKWsqnhGgIF3uoTYP7th32Zej7KNQJdxzOMj+wCfy2Ox3kU7nXErJ36DtYyXDhfiqaiDRw==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-28.1.3.tgz", + "integrity": "sha512-roY3kvrv57Azn1yPgdTebPAXvdR2xfezaKKYzVxZ6It/5NCxzJym6tUI5P1zkdWhfUYkxEI9uZWcQdaFLo8mJQ==", "dev": true, "requires": { - "@jest/core": "^27.4.3", - "@jest/test-result": "^27.4.2", - "@jest/types": "^27.4.2", + "@jest/core": "^28.1.3", + "@jest/test-result": "^28.1.3", + "@jest/types": "^28.1.3", "chalk": "^4.0.0", "exit": "^0.1.2", - "graceful-fs": "^4.2.4", + "graceful-fs": "^4.2.9", "import-local": "^3.0.2", - "jest-config": "^27.4.3", - "jest-util": "^27.4.2", - "jest-validate": "^27.4.2", + "jest-config": "^28.1.3", + "jest-util": "^28.1.3", + "jest-validate": "^28.1.3", "prompts": "^2.0.1", - "yargs": "^16.2.0" + "yargs": "^17.3.1" } }, "jest-config": { - "version": "27.4.3", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.4.3.tgz", - "integrity": "sha512-DQ10HTSqYtC2pO7s9j2jw+li4xUnm2wLYWH2o7K1ftB8NyvToHsXoLlXxtsGh3AW9gUQR6KY/4B7G+T/NswJBw==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-28.1.3.tgz", + "integrity": "sha512-MG3INjByJ0J4AsNBm7T3hsuxKQqFIiRo/AUqb1q9LRKI5UU6Aar9JHbr9Ivn1TVwfUD9KirRoM/T6u8XlcQPHQ==", "dev": true, "requires": { - "@babel/core": "^7.1.0", - "@jest/test-sequencer": "^27.4.2", - "@jest/types": "^27.4.2", - "babel-jest": "^27.4.2", + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^28.1.3", + "@jest/types": "^28.1.3", + "babel-jest": "^28.1.3", "chalk": "^4.0.0", "ci-info": "^3.2.0", "deepmerge": "^4.2.2", - "glob": "^7.1.1", - "graceful-fs": "^4.2.4", - "jest-circus": "^27.4.2", - "jest-environment-jsdom": "^27.4.3", - "jest-environment-node": "^27.4.2", - "jest-get-type": "^27.4.0", - "jest-jasmine2": "^27.4.2", - "jest-regex-util": "^27.4.0", - "jest-resolve": "^27.4.2", - "jest-runner": "^27.4.3", - "jest-util": "^27.4.2", - "jest-validate": "^27.4.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^28.1.3", + "jest-environment-node": "^28.1.3", + "jest-get-type": "^28.0.2", + "jest-regex-util": "^28.0.2", + "jest-resolve": "^28.1.3", + "jest-runner": "^28.1.3", + "jest-util": "^28.1.3", + "jest-validate": "^28.1.3", "micromatch": "^4.0.4", - "pretty-format": "^27.4.2", - "slash": "^3.0.0" + "parse-json": "^5.2.0", + "pretty-format": "^28.1.3", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "@jest/transform": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-28.1.3.tgz", + "integrity": "sha512-u5dT5di+oFI6hfcLOHGTAfmUxFRrjK+vnaP0kkVow9Md/M7V/MxqQMOz/VV25UZO8pzeA9PjfTpOu6BDuwSPQA==", + "dev": true, + "requires": { + "@babel/core": "^7.11.6", + "@jest/types": "^28.1.3", + "@jridgewell/trace-mapping": "^0.3.13", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^28.1.3", + "jest-regex-util": "^28.0.2", + "jest-util": "^28.1.3", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.1" + } + }, + "babel-jest": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-28.1.3.tgz", + "integrity": "sha512-epUaPOEWMk3cWX0M/sPvCHHCe9fMFAa/9hXEgKP8nFfNl/jlGkE9ucq9NqkZGXLDduCJYS0UvSlPUwC0S+rH6Q==", + "dev": true, + "requires": { + "@jest/transform": "^28.1.3", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^28.1.3", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + } + }, + "babel-plugin-jest-hoist": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-28.1.3.tgz", + "integrity": "sha512-Ys3tUKAmfnkRUpPdpa98eYrAR0nV+sSFUZZEGuQ2EbFd1y4SOLtD5QDNHAq+bb9a+bbXvYQC4b+ID/THIMcU6Q==", + "dev": true, + "requires": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + } + }, + "babel-preset-jest": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-28.1.3.tgz", + "integrity": "sha512-L+fupJvlWAHbQfn74coNX3zf60LXMJsezNvvx8eIh7iOR1luJ1poxYgQk1F8PYtNq/6QODDHCqsSnTFSWC491A==", + "dev": true, + "requires": { + "babel-plugin-jest-hoist": "^28.1.3", + "babel-preset-current-node-syntax": "^1.0.0" + } + }, + "jest-get-type": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", + "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "dev": true + }, + "jest-haste-map": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-28.1.3.tgz", + "integrity": "sha512-3S+RQWDXccXDKSWnkHa/dPwt+2qwA8CJzR61w3FoYCvoo3Pn8tvGcysmMF0Bj0EX5RYvAI2EIvC57OmotfdtKA==", + "dev": true, + "requires": { + "@jest/types": "^28.1.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "fsevents": "^2.3.2", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^28.0.2", + "jest-util": "^28.1.3", + "jest-worker": "^28.1.3", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + } + }, + "jest-regex-util": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", + "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==", + "dev": true + }, + "jest-worker": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.3.tgz", + "integrity": "sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==", + "dev": true, + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + } + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "write-file-atomic": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.1.tgz", + "integrity": "sha512-nSKUxgAbyioruk6hU87QzVbY279oYT6uiwgDoujth2ju4mJ+TZau7SQBhtbTmUyuNYTuXnSyRn66FV0+eCgcrQ==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + } + } } }, "jest-date-mock": { @@ -9351,67 +9332,48 @@ "integrity": "sha512-0Lyp+z9xvuNmLbK+5N6FOhSiBeux05Lp5bbveFBmYo40Aggl2wwxFoIrZ+rOWC8nDNcLeBoDd2miQdEDSf3iQw==", "dev": true }, - "jest-diff": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.4.2.tgz", - "integrity": "sha512-ujc9ToyUZDh9KcqvQDkk/gkbf6zSaeEg9AiBxtttXW59H/AcqEYp1ciXAtJp+jXWva5nAf/ePtSsgWwE5mqp4Q==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "diff-sequences": "^27.4.0", - "jest-get-type": "^27.4.0", - "pretty-format": "^27.4.2" - } - }, "jest-docblock": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.4.0.tgz", - "integrity": "sha512-7TBazUdCKGV7svZ+gh7C8esAnweJoG+SvcF6Cjqj4l17zA2q1cMwx2JObSioubk317H+cjcHgP+7fTs60paulg==", + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-28.1.1.tgz", + "integrity": "sha512-3wayBVNiOYx0cwAbl9rwm5kKFP8yHH3d/fkEaL02NPTkDojPtheGB7HZSFY4wzX+DxyrvhXz0KSCVksmCknCuA==", "dev": true, "requires": { "detect-newline": "^3.0.0" } }, "jest-each": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.4.2.tgz", - "integrity": "sha512-53V2MNyW28CTruB3lXaHNk6PkiIFuzdOC9gR3C6j8YE/ACfrPnz+slB0s17AgU1TtxNzLuHyvNlLJ+8QYw9nBg==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-28.1.3.tgz", + "integrity": "sha512-arT1z4sg2yABU5uogObVPvSlSMQlDA48owx07BDPAiasW0yYpYHYOo4HHLz9q0BVzDVU4hILFjzJw0So9aCL/g==", "dev": true, "requires": { - "@jest/types": "^27.4.2", + "@jest/types": "^28.1.3", "chalk": "^4.0.0", - "jest-get-type": "^27.4.0", - "jest-util": "^27.4.2", - "pretty-format": "^27.4.2" - } - }, - "jest-environment-jsdom": { - "version": "27.4.3", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.4.3.tgz", - "integrity": "sha512-x1AUVz3G14LpEJs7KIFUaTINT2n0unOUmvdAby3s/sldUpJJetOJifHo1O/EUQC5fNBowggwJbVulko18y6OWw==", - "dev": true, - "requires": { - "@jest/environment": "^27.4.2", - "@jest/fake-timers": "^27.4.2", - "@jest/types": "^27.4.2", - "@types/node": "*", - "jest-mock": "^27.4.2", - "jest-util": "^27.4.2", - "jsdom": "^16.6.0" + "jest-get-type": "^28.0.2", + "jest-util": "^28.1.3", + "pretty-format": "^28.1.3" + }, + "dependencies": { + "jest-get-type": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", + "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "dev": true + } } }, "jest-environment-node": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.4.2.tgz", - "integrity": "sha512-nzTZ5nJ+FabuZPH2YVci7SZIHpvtNRHPt8+vipLkCnAgXGjVzHm7XJWdnNqXbAkExIgiKeVEkVMNZOZE/LeiIg==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-28.1.3.tgz", + "integrity": "sha512-ugP6XOhEpjAEhGYvp5Xj989ns5cB1K6ZdjBYuS30umT4CQEETaxSiPcZ/E1kFktX4GkrcM4qu07IIlDYX1gp+A==", "dev": true, "requires": { - "@jest/environment": "^27.4.2", - "@jest/fake-timers": "^27.4.2", - "@jest/types": "^27.4.2", + "@jest/environment": "^28.1.3", + "@jest/fake-timers": "^28.1.3", + "@jest/types": "^28.1.3", "@types/node": "*", - "jest-mock": "^27.4.2", - "jest-util": "^27.4.2" + "jest-mock": "^28.1.3", + "jest-util": "^28.1.3" } }, "jest-expect-message": { @@ -9420,105 +9382,86 @@ "integrity": "sha512-WFiXMgwS2lOqQZt1iJMI/hOXpUm32X+ApsuzYcQpW5m16Pv6/Gd9kgC+Q+Q1YVNU04kYcAOv9NXMnjg6kKUy6Q==", "dev": true }, - "jest-get-type": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.4.0.tgz", - "integrity": "sha512-tk9o+ld5TWq41DkK14L4wox4s2D9MtTpKaAVzXfr5CUKm5ZK2ExcaFE0qls2W71zE/6R2TxxrK9w2r6svAFDBQ==", - "dev": true - }, - "jest-haste-map": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.4.2.tgz", - "integrity": "sha512-foiyAEePORUN2eeJnOtcM1y8qW0ShEd9kTjWVL4sVaMcuCJM6gtHegvYPBRT0mpI/bs4ueThM90+Eoj2ncoNsA==", - "dev": true, - "requires": { - "@jest/types": "^27.4.2", - "@types/graceful-fs": "^4.1.2", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "fsevents": "^2.3.2", - "graceful-fs": "^4.2.4", - "jest-regex-util": "^27.4.0", - "jest-serializer": "^27.4.0", - "jest-util": "^27.4.2", - "jest-worker": "^27.4.2", - "micromatch": "^4.0.4", - "walker": "^1.0.7" - } - }, - "jest-jasmine2": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.4.2.tgz", - "integrity": "sha512-VO/fyAJSH9u0THjbteFiL8qc93ufU+yW+bdieDc8tzTCWwlWzO53UHS5nFK1qmE8izb5Smkn+XHlVt6/l06MKQ==", - "dev": true, - "requires": { - "@babel/traverse": "^7.1.0", - "@jest/environment": "^27.4.2", - "@jest/source-map": "^27.4.0", - "@jest/test-result": "^27.4.2", - "@jest/types": "^27.4.2", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "expect": "^27.4.2", - "is-generator-fn": "^2.0.0", - "jest-each": "^27.4.2", - "jest-matcher-utils": "^27.4.2", - "jest-message-util": "^27.4.2", - "jest-runtime": "^27.4.2", - "jest-snapshot": "^27.4.2", - "jest-util": "^27.4.2", - "pretty-format": "^27.4.2", - "throat": "^6.0.1" - } - }, "jest-leak-detector": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.4.2.tgz", - "integrity": "sha512-ml0KvFYZllzPBJWDei3mDzUhyp/M4ubKebX++fPaudpe8OsxUE+m+P6ciVLboQsrzOCWDjE20/eXew9QMx/VGw==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-28.1.3.tgz", + "integrity": "sha512-WFVJhnQsiKtDEo5lG2mM0v40QWnBM+zMdHHyJs8AWZ7J0QZJS59MsyKeJHWhpBZBH32S48FOVvGyOFT1h0DlqA==", "dev": true, "requires": { - "jest-get-type": "^27.4.0", - "pretty-format": "^27.4.2" + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.3" + }, + "dependencies": { + "jest-get-type": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", + "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "dev": true + } } }, "jest-matcher-utils": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.4.2.tgz", - "integrity": "sha512-jyP28er3RRtMv+fmYC/PKG8wvAmfGcSNproVTW2Y0P/OY7/hWUOmsPfxN1jOhM+0u2xU984u2yEagGivz9OBGQ==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-28.1.3.tgz", + "integrity": "sha512-kQeJ7qHemKfbzKoGjHHrRKH6atgxMk8Enkk2iPQ3XwO6oE/KYD8lMYOziCkeSB9G4adPM4nR1DE8Tf5JeWH6Bw==", "dev": true, "requires": { "chalk": "^4.0.0", - "jest-diff": "^27.4.2", - "jest-get-type": "^27.4.0", - "pretty-format": "^27.4.2" + "jest-diff": "^28.1.3", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.3" + }, + "dependencies": { + "diff-sequences": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.1.1.tgz", + "integrity": "sha512-FU0iFaH/E23a+a718l8Qa/19bF9p06kgE0KipMOMadwa3SjnaElKzPaUC0vnibs6/B/9ni97s61mcejk8W1fQw==", + "dev": true + }, + "jest-diff": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.1.3.tgz", + "integrity": "sha512-8RqP1B/OXzjjTWkqMX67iqgwBVJRgCyKD3L9nq+6ZqJMdvjE8RgHktqZ6jNrkdMT+dJuYNI3rhQpxaz7drJHfw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "diff-sequences": "^28.1.1", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.3" + } + }, + "jest-get-type": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", + "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "dev": true + } } }, "jest-message-util": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.4.2.tgz", - "integrity": "sha512-OMRqRNd9E0DkBLZpFtZkAGYOXl6ZpoMtQJWTAREJKDOFa0M6ptB7L67tp+cszMBkvSgKOhNtQp2Vbcz3ZZKo/w==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.3.tgz", + "integrity": "sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g==", "dev": true, "requires": { "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.4.2", + "@jest/types": "^28.1.3", "@types/stack-utils": "^2.0.0", "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", + "graceful-fs": "^4.2.9", "micromatch": "^4.0.4", - "pretty-format": "^27.4.2", + "pretty-format": "^28.1.3", "slash": "^3.0.0", "stack-utils": "^2.0.3" } }, "jest-mock": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.4.2.tgz", - "integrity": "sha512-PDDPuyhoukk20JrQKeofK12hqtSka7mWH0QQuxSNgrdiPsrnYYLS6wbzu/HDlxZRzji5ylLRULeuI/vmZZDrYA==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-28.1.3.tgz", + "integrity": "sha512-o3J2jr6dMMWYVH4Lh/NKmDXdosrsJgi4AviS8oXLujcjpCMBb1FMsblDnOXKZKfSiHLxYub1eS0IHuRXsio9eA==", "dev": true, "requires": { - "@jest/types": "^27.4.2", + "@jest/types": "^28.1.3", "@types/node": "*" } }, @@ -9529,231 +9472,522 @@ "dev": true, "requires": {} }, - "jest-regex-util": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.4.0.tgz", - "integrity": "sha512-WeCpMpNnqJYMQoOjm1nTtsgbR4XHAk1u00qDoNBQoykM280+/TmgA5Qh5giC1ecy6a5d4hbSsHzpBtu5yvlbEg==", - "dev": true - }, "jest-resolve": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.4.2.tgz", - "integrity": "sha512-d/zqPjxCzMqHlOdRTg8cTpO9jY+1/T74KazT8Ws/LwmwxV5sRMWOkiLjmzUCDj/5IqA5XHNK4Hkmlq9Kdpb9Sg==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-28.1.3.tgz", + "integrity": "sha512-Z1W3tTjE6QaNI90qo/BJpfnvpxtaFTFw5CDgwpyE/Kz8U/06N1Hjf4ia9quUhCh39qIGWF1ZuxFiBiJQwSEYKQ==", "dev": true, "requires": { - "@jest/types": "^27.4.2", "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.4.2", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^28.1.3", "jest-pnp-resolver": "^1.2.2", - "jest-util": "^27.4.2", - "jest-validate": "^27.4.2", + "jest-util": "^28.1.3", + "jest-validate": "^28.1.3", "resolve": "^1.20.0", "resolve.exports": "^1.1.0", "slash": "^3.0.0" + }, + "dependencies": { + "jest-haste-map": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-28.1.3.tgz", + "integrity": "sha512-3S+RQWDXccXDKSWnkHa/dPwt+2qwA8CJzR61w3FoYCvoo3Pn8tvGcysmMF0Bj0EX5RYvAI2EIvC57OmotfdtKA==", + "dev": true, + "requires": { + "@jest/types": "^28.1.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "fsevents": "^2.3.2", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^28.0.2", + "jest-util": "^28.1.3", + "jest-worker": "^28.1.3", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + } + }, + "jest-regex-util": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", + "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==", + "dev": true + }, + "jest-worker": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.3.tgz", + "integrity": "sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==", + "dev": true, + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + } + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "jest-resolve-dependencies": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.4.2.tgz", - "integrity": "sha512-hb++cTpqvOWfU49MCP/JQkxmnrhKoAVqXWFjgYXswRSVGk8Q6bDTSvhbCeYXDtXaymY0y7WrrSIlKogClcKJuw==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-28.1.3.tgz", + "integrity": "sha512-qa0QO2Q0XzQoNPouMbCc7Bvtsem8eQgVPNkwn9LnS+R2n8DaVDPL/U1gngC0LTl1RYXJU0uJa2BMC2DbTfFrHA==", "dev": true, "requires": { - "@jest/types": "^27.4.2", - "jest-regex-util": "^27.4.0", - "jest-snapshot": "^27.4.2" + "jest-regex-util": "^28.0.2", + "jest-snapshot": "^28.1.3" + }, + "dependencies": { + "jest-regex-util": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", + "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==", + "dev": true + } } }, "jest-runner": { - "version": "27.4.3", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.4.3.tgz", - "integrity": "sha512-JgR6Om/j22Fd6ZUUIGTWNcCtuZVYbNrecb4k89W4UyFJoRtHpo2zMKWkmFFFJoqwWGrfrcPLnVBIgkJiTV3cyA==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-28.1.3.tgz", + "integrity": "sha512-GkMw4D/0USd62OVO0oEgjn23TM+YJa2U2Wu5zz9xsQB1MxWKDOlrnykPxnMsN0tnJllfLPinHTka61u0QhaxBA==", "dev": true, "requires": { - "@jest/console": "^27.4.2", - "@jest/environment": "^27.4.2", - "@jest/test-result": "^27.4.2", - "@jest/transform": "^27.4.2", - "@jest/types": "^27.4.2", + "@jest/console": "^28.1.3", + "@jest/environment": "^28.1.3", + "@jest/test-result": "^28.1.3", + "@jest/transform": "^28.1.3", + "@jest/types": "^28.1.3", "@types/node": "*", "chalk": "^4.0.0", - "emittery": "^0.8.1", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "jest-docblock": "^27.4.0", - "jest-environment-jsdom": "^27.4.3", - "jest-environment-node": "^27.4.2", - "jest-haste-map": "^27.4.2", - "jest-leak-detector": "^27.4.2", - "jest-message-util": "^27.4.2", - "jest-resolve": "^27.4.2", - "jest-runtime": "^27.4.2", - "jest-util": "^27.4.2", - "jest-worker": "^27.4.2", - "source-map-support": "^0.5.6", - "throat": "^6.0.1" + "emittery": "^0.10.2", + "graceful-fs": "^4.2.9", + "jest-docblock": "^28.1.1", + "jest-environment-node": "^28.1.3", + "jest-haste-map": "^28.1.3", + "jest-leak-detector": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-resolve": "^28.1.3", + "jest-runtime": "^28.1.3", + "jest-util": "^28.1.3", + "jest-watcher": "^28.1.3", + "jest-worker": "^28.1.3", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "dependencies": { + "@jest/transform": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-28.1.3.tgz", + "integrity": "sha512-u5dT5di+oFI6hfcLOHGTAfmUxFRrjK+vnaP0kkVow9Md/M7V/MxqQMOz/VV25UZO8pzeA9PjfTpOu6BDuwSPQA==", + "dev": true, + "requires": { + "@babel/core": "^7.11.6", + "@jest/types": "^28.1.3", + "@jridgewell/trace-mapping": "^0.3.13", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^28.1.3", + "jest-regex-util": "^28.0.2", + "jest-util": "^28.1.3", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.1" + } + }, + "jest-haste-map": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-28.1.3.tgz", + "integrity": "sha512-3S+RQWDXccXDKSWnkHa/dPwt+2qwA8CJzR61w3FoYCvoo3Pn8tvGcysmMF0Bj0EX5RYvAI2EIvC57OmotfdtKA==", + "dev": true, + "requires": { + "@jest/types": "^28.1.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "fsevents": "^2.3.2", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^28.0.2", + "jest-util": "^28.1.3", + "jest-worker": "^28.1.3", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + } + }, + "jest-regex-util": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", + "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==", + "dev": true + }, + "jest-worker": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.3.tgz", + "integrity": "sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==", + "dev": true, + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + } + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "write-file-atomic": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.1.tgz", + "integrity": "sha512-nSKUxgAbyioruk6hU87QzVbY279oYT6uiwgDoujth2ju4mJ+TZau7SQBhtbTmUyuNYTuXnSyRn66FV0+eCgcrQ==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + } + } } }, "jest-runtime": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.4.2.tgz", - "integrity": "sha512-eqPgcBaUNaw6j8T5M+dnfAEh6MIrh2YmtskCr9sl50QYpD22Sg+QqHw3J3nmaLzVMbBtOMHFFxLF0Qx8MsZVFQ==", - "dev": true, - "requires": { - "@jest/console": "^27.4.2", - "@jest/environment": "^27.4.2", - "@jest/globals": "^27.4.2", - "@jest/source-map": "^27.4.0", - "@jest/test-result": "^27.4.2", - "@jest/transform": "^27.4.2", - "@jest/types": "^27.4.2", - "@types/yargs": "^16.0.0", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-28.1.3.tgz", + "integrity": "sha512-NU+881ScBQQLc1JHG5eJGU7Ui3kLKrmwCPPtYsJtBykixrM2OhVQlpMmFWJjMyDfdkGgBMNjXCGB/ebzsgNGQw==", + "dev": true, + "requires": { + "@jest/environment": "^28.1.3", + "@jest/fake-timers": "^28.1.3", + "@jest/globals": "^28.1.3", + "@jest/source-map": "^28.1.2", + "@jest/test-result": "^28.1.3", + "@jest/transform": "^28.1.3", + "@jest/types": "^28.1.3", "chalk": "^4.0.0", "cjs-module-lexer": "^1.0.0", "collect-v8-coverage": "^1.0.0", "execa": "^5.0.0", - "exit": "^0.1.2", "glob": "^7.1.3", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.4.2", - "jest-message-util": "^27.4.2", - "jest-mock": "^27.4.2", - "jest-regex-util": "^27.4.0", - "jest-resolve": "^27.4.2", - "jest-snapshot": "^27.4.2", - "jest-util": "^27.4.2", - "jest-validate": "^27.4.2", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-mock": "^28.1.3", + "jest-regex-util": "^28.0.2", + "jest-resolve": "^28.1.3", + "jest-snapshot": "^28.1.3", + "jest-util": "^28.1.3", "slash": "^3.0.0", - "strip-bom": "^4.0.0", - "yargs": "^16.2.0" - } - }, - "jest-serializer": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.4.0.tgz", - "integrity": "sha512-RDhpcn5f1JYTX2pvJAGDcnsNTnsV9bjYPU8xcV+xPwOXnUPOQwf4ZEuiU6G9H1UztH+OapMgu/ckEVwO87PwnQ==", - "dev": true, - "requires": { - "@types/node": "*", - "graceful-fs": "^4.2.4" + "strip-bom": "^4.0.0" + }, + "dependencies": { + "@jest/transform": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-28.1.3.tgz", + "integrity": "sha512-u5dT5di+oFI6hfcLOHGTAfmUxFRrjK+vnaP0kkVow9Md/M7V/MxqQMOz/VV25UZO8pzeA9PjfTpOu6BDuwSPQA==", + "dev": true, + "requires": { + "@babel/core": "^7.11.6", + "@jest/types": "^28.1.3", + "@jridgewell/trace-mapping": "^0.3.13", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^28.1.3", + "jest-regex-util": "^28.0.2", + "jest-util": "^28.1.3", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.1" + } + }, + "jest-haste-map": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-28.1.3.tgz", + "integrity": "sha512-3S+RQWDXccXDKSWnkHa/dPwt+2qwA8CJzR61w3FoYCvoo3Pn8tvGcysmMF0Bj0EX5RYvAI2EIvC57OmotfdtKA==", + "dev": true, + "requires": { + "@jest/types": "^28.1.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "fsevents": "^2.3.2", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^28.0.2", + "jest-util": "^28.1.3", + "jest-worker": "^28.1.3", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + } + }, + "jest-regex-util": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", + "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==", + "dev": true + }, + "jest-worker": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.3.tgz", + "integrity": "sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==", + "dev": true, + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + } + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "write-file-atomic": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.1.tgz", + "integrity": "sha512-nSKUxgAbyioruk6hU87QzVbY279oYT6uiwgDoujth2ju4mJ+TZau7SQBhtbTmUyuNYTuXnSyRn66FV0+eCgcrQ==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + } + } } }, "jest-snapshot": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.4.2.tgz", - "integrity": "sha512-DI7lJlNIu6WSQ+esqhnJzEzU70+dV+cNjoF1c+j5FagWEd3KtOyZvVliAH0RWNQ6KSnAAnKSU0qxJ8UXOOhuUQ==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-28.1.3.tgz", + "integrity": "sha512-4lzMgtiNlc3DU/8lZfmqxN3AYD6GGLbl+72rdBpXvcV+whX7mDrREzkPdp2RnmfIiWBg1YbuFSkXduF2JcafJg==", "dev": true, "requires": { - "@babel/core": "^7.7.2", + "@babel/core": "^7.11.6", "@babel/generator": "^7.7.2", - "@babel/parser": "^7.7.2", "@babel/plugin-syntax-typescript": "^7.7.2", "@babel/traverse": "^7.7.2", - "@babel/types": "^7.0.0", - "@jest/transform": "^27.4.2", - "@jest/types": "^27.4.2", - "@types/babel__traverse": "^7.0.4", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^28.1.3", + "@jest/transform": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/babel__traverse": "^7.0.6", "@types/prettier": "^2.1.5", "babel-preset-current-node-syntax": "^1.0.0", "chalk": "^4.0.0", - "expect": "^27.4.2", - "graceful-fs": "^4.2.4", - "jest-diff": "^27.4.2", - "jest-get-type": "^27.4.0", - "jest-haste-map": "^27.4.2", - "jest-matcher-utils": "^27.4.2", - "jest-message-util": "^27.4.2", - "jest-resolve": "^27.4.2", - "jest-util": "^27.4.2", + "expect": "^28.1.3", + "graceful-fs": "^4.2.9", + "jest-diff": "^28.1.3", + "jest-get-type": "^28.0.2", + "jest-haste-map": "^28.1.3", + "jest-matcher-utils": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-util": "^28.1.3", "natural-compare": "^1.4.0", - "pretty-format": "^27.4.2", - "semver": "^7.3.2" + "pretty-format": "^28.1.3", + "semver": "^7.3.5" }, "dependencies": { + "@jest/transform": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-28.1.3.tgz", + "integrity": "sha512-u5dT5di+oFI6hfcLOHGTAfmUxFRrjK+vnaP0kkVow9Md/M7V/MxqQMOz/VV25UZO8pzeA9PjfTpOu6BDuwSPQA==", + "dev": true, + "requires": { + "@babel/core": "^7.11.6", + "@jest/types": "^28.1.3", + "@jridgewell/trace-mapping": "^0.3.13", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^28.1.3", + "jest-regex-util": "^28.0.2", + "jest-util": "^28.1.3", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.1" + } + }, + "diff-sequences": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.1.1.tgz", + "integrity": "sha512-FU0iFaH/E23a+a718l8Qa/19bF9p06kgE0KipMOMadwa3SjnaElKzPaUC0vnibs6/B/9ni97s61mcejk8W1fQw==", + "dev": true + }, + "jest-diff": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.1.3.tgz", + "integrity": "sha512-8RqP1B/OXzjjTWkqMX67iqgwBVJRgCyKD3L9nq+6ZqJMdvjE8RgHktqZ6jNrkdMT+dJuYNI3rhQpxaz7drJHfw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "diff-sequences": "^28.1.1", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.3" + } + }, + "jest-get-type": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", + "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "dev": true + }, + "jest-haste-map": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-28.1.3.tgz", + "integrity": "sha512-3S+RQWDXccXDKSWnkHa/dPwt+2qwA8CJzR61w3FoYCvoo3Pn8tvGcysmMF0Bj0EX5RYvAI2EIvC57OmotfdtKA==", + "dev": true, + "requires": { + "@jest/types": "^28.1.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "fsevents": "^2.3.2", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^28.0.2", + "jest-util": "^28.1.3", + "jest-worker": "^28.1.3", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + } + }, + "jest-regex-util": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", + "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==", + "dev": true + }, + "jest-worker": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.3.tgz", + "integrity": "sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==", + "dev": true, + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + } + }, "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dev": true, "requires": { "lru-cache": "^6.0.0" } + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "write-file-atomic": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.1.tgz", + "integrity": "sha512-nSKUxgAbyioruk6hU87QzVbY279oYT6uiwgDoujth2ju4mJ+TZau7SQBhtbTmUyuNYTuXnSyRn66FV0+eCgcrQ==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + } } } }, "jest-util": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.4.2.tgz", - "integrity": "sha512-YuxxpXU6nlMan9qyLuxHaMMOzXAl5aGZWCSzben5DhLHemYQxCc4YK+4L3ZrCutT8GPQ+ui9k5D8rUJoDioMnA==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", + "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", "dev": true, "requires": { - "@jest/types": "^27.4.2", + "@jest/types": "^28.1.3", "@types/node": "*", "chalk": "^4.0.0", "ci-info": "^3.2.0", - "graceful-fs": "^4.2.4", + "graceful-fs": "^4.2.9", "picomatch": "^2.2.3" } }, "jest-validate": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.4.2.tgz", - "integrity": "sha512-hWYsSUej+Fs8ZhOm5vhWzwSLmVaPAxRy+Mr+z5MzeaHm9AxUpXdoVMEW4R86y5gOobVfBsMFLk4Rb+QkiEpx1A==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-28.1.3.tgz", + "integrity": "sha512-SZbOGBWEsaTxBGCOpsRWlXlvNkvTkY0XxRfh7zYmvd8uL5Qzyg0CHAXiXKROflh801quA6+/DsT4ODDthOC/OA==", "dev": true, "requires": { - "@jest/types": "^27.4.2", + "@jest/types": "^28.1.3", "camelcase": "^6.2.0", "chalk": "^4.0.0", - "jest-get-type": "^27.4.0", + "jest-get-type": "^28.0.2", "leven": "^3.1.0", - "pretty-format": "^27.4.2" + "pretty-format": "^28.1.3" }, "dependencies": { "camelcase": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.1.tgz", - "integrity": "sha512-tVI4q5jjFV5CavAU8DXfza/TJcZutVKo/5Foskmsqcm0MsL91moHvwiGNnqaa2o6PF/7yT5ikDRcVcl8Rj6LCA==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true + }, + "jest-get-type": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", + "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", "dev": true } } }, "jest-watcher": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.4.2.tgz", - "integrity": "sha512-NJvMVyyBeXfDezhWzUOCOYZrUmkSCiatpjpm+nFUid74OZEHk6aMLrZAukIiFDwdbqp6mTM6Ui1w4oc+8EobQg==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-28.1.3.tgz", + "integrity": "sha512-t4qcqj9hze+jviFPUN3YAtAEeFnr/azITXQEMARf5cMwKY2SMBRnCQTXLixTl20OR6mLh9KLMrgVJgJISym+1g==", "dev": true, "requires": { - "@jest/test-result": "^27.4.2", - "@jest/types": "^27.4.2", + "@jest/test-result": "^28.1.3", + "@jest/types": "^28.1.3", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", - "jest-util": "^27.4.2", + "emittery": "^0.10.2", + "jest-util": "^28.1.3", "string-length": "^4.0.1" } }, - "jest-worker": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.4.2.tgz", - "integrity": "sha512-0QMy/zPovLfUPyHuOuuU4E+kGACXXE84nRnq6lBVI9GJg5DCBiA97SATi+ZP8CpiJwEQy1oCPjRBf8AnLjN+Ag==", - "dev": true, - "requires": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "dependencies": { - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -9768,54 +10002,22 @@ "argparse": "^2.0.1" } }, - "jsdom": { - "version": "16.7.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", - "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", - "dev": true, - "requires": { - "abab": "^2.0.5", - "acorn": "^8.2.4", - "acorn-globals": "^6.0.0", - "cssom": "^0.4.4", - "cssstyle": "^2.3.0", - "data-urls": "^2.0.0", - "decimal.js": "^10.2.1", - "domexception": "^2.0.1", - "escodegen": "^2.0.0", - "form-data": "^3.0.0", - "html-encoding-sniffer": "^2.0.1", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.0", - "parse5": "6.0.1", - "saxes": "^5.0.1", - "symbol-tree": "^3.2.4", - "tough-cookie": "^4.0.0", - "w3c-hr-time": "^1.0.2", - "w3c-xmlserializer": "^2.0.0", - "webidl-conversions": "^6.1.0", - "whatwg-encoding": "^1.0.5", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.5.0", - "ws": "^7.4.6", - "xml-name-validator": "^3.0.0" - } - }, "jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", "dev": true }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, "json5": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", - "requires": { - "minimist": "^1.2.5" - } + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", + "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==" }, "kleur": { "version": "3.0.3", @@ -9829,21 +10031,17 @@ "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", "dev": true }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - } - }, "libphonenumber-js": { "version": "1.9.34", "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.9.34.tgz", "integrity": "sha512-gHTNU9xTtVgSp30IDX/57W4pETMXDIYXFfwEOJVXiYosiY7Hc7ogJwlBjOqlCcU04X0aA8DT57hdwUC1sJBJnA==" }, + "lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, "locate-path": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", @@ -9853,12 +10051,6 @@ "p-locate": "^4.1.0" } }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, "lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", @@ -10046,7 +10238,7 @@ "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, "negotiator": { @@ -10089,12 +10281,6 @@ "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", "dev": true }, - "node-modules-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", - "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=", - "dev": true - }, "node-releases": { "version": "1.1.75", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.75.tgz", @@ -10132,12 +10318,6 @@ "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" }, - "nwsapi": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", - "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", - "dev": true - }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -10174,20 +10354,6 @@ "mimic-fn": "^2.1.0" } }, - "optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dev": true, - "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - } - }, "p-limit": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", @@ -10217,11 +10383,17 @@ "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" }, - "parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true + "parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + } }, "parseurl": { "version": "1.3.3", @@ -10327,13 +10499,10 @@ "dev": true }, "pirates": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", - "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==", - "dev": true, - "requires": { - "node-modules-regexp": "^1.0.0" - } + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", + "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", + "dev": true }, "pkg-dir": { "version": "4.2.0", @@ -10387,27 +10556,21 @@ "tunnel-agent": "^0.6.0" } }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true - }, "prettier": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.6.2.tgz", "integrity": "sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew==" }, "pretty-format": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.4.2.tgz", - "integrity": "sha512-p0wNtJ9oLuvgOQDEIZ9zQjZffK7KtyR6Si0jnXULIDwrlNF8Cuir3AZP0hHv0jmKuNN/edOnbMjnzd4uTcmWiw==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", + "integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==", "dev": true, "requires": { - "@jest/types": "^27.4.2", + "@jest/schemas": "^28.1.3", "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" + "react-is": "^18.0.0" }, "dependencies": { "ansi-styles": { @@ -10442,12 +10605,6 @@ "ipaddr.js": "1.9.1" } }, - "psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", - "dev": true - }, "pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", @@ -10457,12 +10614,6 @@ "once": "^1.3.1" } }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true - }, "qs": { "version": "6.9.7", "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz", @@ -10496,9 +10647,9 @@ } }, "react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", "dev": true }, "readable-stream": { @@ -10523,17 +10674,18 @@ "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "dev": true }, "resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", "dev": true, "requires": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" } }, "resolve-cwd": { @@ -10576,15 +10728,6 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, - "saxes": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", - "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", - "dev": true, - "requires": { - "xmlchars": "^2.2.0" - } - }, "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", @@ -10666,9 +10809,9 @@ } }, "signal-exit": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.4.tgz", - "integrity": "sha512-rqYhcAnZ6d/vTPGghdrw7iumdcbXpsk1b8IG/rz+VWV51DM0p7XCtMoJ3qhPLIbp3tvyt3pKRbaaEMZYpHto8Q==" + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, "simple-concat": { "version": "1.0.1", @@ -10713,9 +10856,9 @@ "dev": true }, "source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", "dev": true, "requires": { "buffer-from": "^1.0.0", @@ -10916,10 +11059,10 @@ "supports-color": "^7.0.0" } }, - "symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true }, "tar": { @@ -10998,12 +11141,6 @@ "minimatch": "^3.0.4" } }, - "throat": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.1.tgz", - "integrity": "sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w==", - "dev": true - }, "timers-ext": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz", @@ -11034,41 +11171,20 @@ "is-number": "^7.0.0" } }, - "tough-cookie": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", - "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", - "dev": true, - "requires": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.1.2" - } - }, - "tr46": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", - "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", - "dev": true, - "requires": { - "punycode": "^2.1.1" - } - }, "ts-jest": { - "version": "27.1.0", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-27.1.0.tgz", - "integrity": "sha512-ZouWlP03JMtzfNHg0ZeDrxAESYGmVhWyHtIl2/01kBbXaMbTr4Vhv6/GeMxUed6GFg/4ycMo+yU6Eo9gI16xTQ==", + "version": "28.0.7", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-28.0.7.tgz", + "integrity": "sha512-wWXCSmTwBVmdvWrOpYhal79bDpioDy4rTT+0vyUnE3ZzM7LOAAGG9NXwzkEL/a516rQEgnMmS/WKP9jBPCVJyA==", "dev": true, "requires": { "bs-logger": "0.x", - "esbuild": "~0.14.0", "fast-json-stable-stringify": "2.x", - "jest-util": "^27.0.0", - "json5": "2.x", + "jest-util": "^28.0.0", + "json5": "^2.2.1", "lodash.memoize": "4.x", "make-error": "1.x", "semver": "7.x", - "yargs-parser": "20.x" + "yargs-parser": "^21.0.1" }, "dependencies": { "semver": { @@ -11152,15 +11268,6 @@ "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2" - } - }, "type-detect": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", @@ -11182,26 +11289,11 @@ "mime-types": "~2.1.24" } }, - "typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dev": true, - "requires": { - "is-typedarray": "^1.0.0" - } - }, "typescript": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.3.tgz", "integrity": "sha512-4xfscpisVgqqDfPaJo5vkd+Qd/ItkoagnHpufr+i2QCHBsNYp+G7UAoyFl8aPtx879u38wPV65rZ8qbGZijalA==" }, - "universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true - }, "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -11223,22 +11315,14 @@ "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" }, "v8-to-istanbul": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.0.tgz", - "integrity": "sha512-/PRhfd8aTNp9Ggr62HPzXg2XasNFGy5PBt0Rp04du7/8GNNSgxFL6WBTkgMKSL9bFjH+8kKEG3f37FmxiTqUUA==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz", + "integrity": "sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==", "dev": true, "requires": { + "@jridgewell/trace-mapping": "^0.3.12", "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0", - "source-map": "^0.7.3" - }, - "dependencies": { - "source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true - } + "convert-source-map": "^1.6.0" } }, "vary": { @@ -11246,24 +11330,6 @@ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" }, - "w3c-hr-time": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", - "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", - "dev": true, - "requires": { - "browser-process-hrtime": "^1.0.0" - } - }, - "w3c-xmlserializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", - "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", - "dev": true, - "requires": { - "xml-name-validator": "^3.0.0" - } - }, "walker": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", @@ -11273,38 +11339,6 @@ "makeerror": "1.0.12" } }, - "webidl-conversions": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", - "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", - "dev": true - }, - "whatwg-encoding": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", - "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", - "dev": true, - "requires": { - "iconv-lite": "0.4.24" - } - }, - "whatwg-mimetype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", - "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", - "dev": true - }, - "whatwg-url": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", - "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", - "dev": true, - "requires": { - "lodash": "^4.7.0", - "tr46": "^2.1.0", - "webidl-conversions": "^6.1.0" - } - }, "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -11322,12 +11356,6 @@ "string-width": "^1.0.2 || 2" } }, - "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true - }, "wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -11363,37 +11391,6 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, - "write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "dev": true, - "requires": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "ws": { - "version": "7.5.6", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.6.tgz", - "integrity": "sha512-6GLgCqo2cy2A2rjCNFlxQS6ZljG/coZfZXclldI8FB/1G3CCI36Zd8xy2HrFVACi8tfk5XrgLQEk+P0Tnz9UcA==", - "dev": true, - "requires": {} - }, - "xml-name-validator": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", - "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", - "dev": true - }, - "xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "dev": true - }, "xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -11411,18 +11408,18 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "version": "17.5.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", + "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", "dev": true, "requires": { "cliui": "^7.0.2", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "string-width": "^4.2.0", + "string-width": "^4.2.3", "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" + "yargs-parser": "^21.0.0" }, "dependencies": { "is-fullwidth-code-point": { @@ -11445,15 +11442,21 @@ } }, "yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "version": "21.0.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.1.tgz", + "integrity": "sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==", "dev": true }, "yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==" + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true } } } diff --git a/examples/todo-sqlite/package.json b/examples/todo-sqlite/package.json index 3536dc135..8f36d1f80 100644 --- a/examples/todo-sqlite/package.json +++ b/examples/todo-sqlite/package.json @@ -22,22 +22,22 @@ "devDependencies": { "@snowtop/ent-graphql-tests": "^0.1.0-alpha3", "@types/express": "^4.17.11", - "@types/jest": "^27.0.1", + "@types/jest": "^28.1.6", "@types/jest-expect-message": "^1.0.3", "@types/supertest": "^2.0.11", "@types/uuid": "^8.3.1", - "jest": "^27.4.3", + "jest": "^28.1.3", "jest-date-mock": "^1.0.8", "jest-expect-message": "^1.0.2", "supertest": "^6.1.3", - "ts-jest": "^27.1.0", + "ts-jest": "^28.0.7", "tsconfig-paths": "^3.11.0", "uuid": "^8.3.2" }, "dependencies": { - "@snowtop/ent": "^0.1.0-alpha51", + "@snowtop/ent": "^0.1.0-alpha55", "@snowtop/ent-phonenumber": "^0.1.0-alpha1", - "@snowtop/ent-soft-delete": "^0.1.0-alpha1", + "@snowtop/ent-soft-delete": "^0.1.0-alpha3", "@types/node": "^15.0.3", "@types/pg": "^8.6.1", "better-sqlite3": "^7.4.3", diff --git a/examples/todo-sqlite/src/ent/edge/custom_edge.ts b/examples/todo-sqlite/src/ent/edge/custom_edge.ts new file mode 100644 index 000000000..5fa38713a --- /dev/null +++ b/examples/todo-sqlite/src/ent/edge/custom_edge.ts @@ -0,0 +1,9 @@ +import { Data, AssocEdge } from "@snowtop/ent"; + +export class CustomTodoEdge extends AssocEdge { + deletedAt: Date | null = null; + constructor(data: Data) { + super(data); + this.deletedAt = data.deleted_at; + } +} diff --git a/examples/todo-sqlite/src/ent/generated/account_base.ts b/examples/todo-sqlite/src/ent/generated/account_base.ts index 4d9f598cf..b37d13341 100644 --- a/examples/todo-sqlite/src/ent/generated/account_base.ts +++ b/examples/todo-sqlite/src/ent/generated/account_base.ts @@ -11,6 +11,7 @@ import { PrivacyPolicy, Viewer, convertDate, + convertNullableDate, loadCustomData, loadCustomEnts, loadEnt, @@ -29,8 +30,6 @@ import { import { AccountToTagsQuery, AccountToTodosQuery, - DeletedAtMixin, - IDeletedAt, NodeType, } from "src/ent/internal"; import schema from "src/schema/account_schema"; @@ -52,24 +51,21 @@ interface AccountDBData { account_state: AccountState | null; } -export class AccountBase - extends DeletedAtMixin(class {}) - implements Ent, IDeletedAt -{ +export class AccountBase implements Ent { readonly nodeType = NodeType.Account; readonly id: ID; readonly createdAt: Date; readonly updatedAt: Date; + protected readonly deletedAt: Date | null; readonly name: string; readonly phoneNumber: string | null; readonly accountState: AccountState | null; constructor(public viewer: Viewer, protected data: Data) { - // @ts-ignore pass to mixin - super(viewer, data); this.id = data.id; this.createdAt = convertDate(data.created_at); this.updatedAt = convertDate(data.updated_at); + this.deletedAt = convertNullableDate(data.deleted_at); this.name = data.name; this.phoneNumber = data.phone_number; this.accountState = data.account_state; diff --git a/examples/todo-sqlite/src/ent/generated/mixins/deleted_at.ts b/examples/todo-sqlite/src/ent/generated/mixins/deleted_at.ts deleted file mode 100644 index 7c3febc78..000000000 --- a/examples/todo-sqlite/src/ent/generated/mixins/deleted_at.ts +++ /dev/null @@ -1,37 +0,0 @@ -// Generated by github.com/lolopinto/ent/ent, DO NOT EDIT. - -import { Data, Viewer, convertNullableDate } from "@snowtop/ent"; - -type Constructor = new (...args: any[]) => T; - -export interface IDeletedAt { - isDeletedAt(): boolean; - deletedAt: Date | null; -} - -function extractFromArgs( - args: any[], -): { viewer: TViewer; data: TData } { - if (args.length !== 2) { - throw new Error("args should be length 2"); - } - return { - viewer: args[0], - data: args[1], - }; -} - -export function DeletedAtMixin(BaseClass: T) { - return class DeletedAtMixin extends BaseClass { - readonly deletedAt: Date | null; - constructor(...args: any[]) { - super(...args); - const { data } = extractFromArgs(args); - this.deletedAt = convertNullableDate(data.deleted_at); - } - - isDeletedAt() { - return true; - } - }; -} diff --git a/examples/todo-sqlite/src/ent/generated/tag_base.ts b/examples/todo-sqlite/src/ent/generated/tag_base.ts index 9ed3c2e50..7858a598d 100644 --- a/examples/todo-sqlite/src/ent/generated/tag_base.ts +++ b/examples/todo-sqlite/src/ent/generated/tag_base.ts @@ -11,6 +11,7 @@ import { PrivacyPolicy, Viewer, convertDate, + convertNullableDate, convertNullableList, loadCustomData, loadCustomEnts, @@ -24,14 +25,7 @@ import { tagLoaderInfo, tagNoTransformLoader, } from "src/ent/generated/loaders"; -import { - Account, - DeletedAtMixin, - IDeletedAt, - NodeType, - Tag, - TagToTodosQuery, -} from "src/ent/internal"; +import { Account, NodeType, Tag, TagToTodosQuery } from "src/ent/internal"; import schema from "src/schema/tag_schema"; interface TagDBData { @@ -45,25 +39,22 @@ interface TagDBData { related_tag_ids: ID[] | null; } -export class TagBase - extends DeletedAtMixin(class {}) - implements Ent, IDeletedAt -{ +export class TagBase implements Ent { readonly nodeType = NodeType.Tag; readonly id: ID; readonly createdAt: Date; readonly updatedAt: Date; + protected readonly deletedAt: Date | null; readonly displayName: string; readonly canonicalName: string; readonly ownerID: ID; readonly relatedTagIds: ID[] | null; constructor(public viewer: Viewer, protected data: Data) { - // @ts-ignore pass to mixin - super(viewer, data); this.id = data.id; this.createdAt = convertDate(data.created_at); this.updatedAt = convertDate(data.updated_at); + this.deletedAt = convertNullableDate(data.deleted_at); this.displayName = data.display_name; this.canonicalName = data.canonical_name; this.ownerID = data.owner_id; diff --git a/examples/todo-sqlite/src/ent/generated/todo_base.ts b/examples/todo-sqlite/src/ent/generated/todo_base.ts index ef7fb84bb..5c1b293d5 100644 --- a/examples/todo-sqlite/src/ent/generated/todo_base.ts +++ b/examples/todo-sqlite/src/ent/generated/todo_base.ts @@ -12,6 +12,7 @@ import { Viewer, convertBool, convertDate, + convertNullableDate, loadCustomData, loadCustomEnts, loadEnt, @@ -24,13 +25,7 @@ import { todoLoaderInfo, todoNoTransformLoader, } from "src/ent/generated/loaders"; -import { - Account, - DeletedAtMixin, - IDeletedAt, - NodeType, - TodoToTagsQuery, -} from "src/ent/internal"; +import { Account, NodeType, TodoToTagsQuery } from "src/ent/internal"; import schema from "src/schema/todo_schema"; interface TodoDBData { @@ -43,24 +38,21 @@ interface TodoDBData { creator_id: ID; } -export class TodoBase - extends DeletedAtMixin(class {}) - implements Ent, IDeletedAt -{ +export class TodoBase implements Ent { readonly nodeType = NodeType.Todo; readonly id: ID; readonly createdAt: Date; readonly updatedAt: Date; + protected readonly deletedAt: Date | null; readonly text: string; readonly completed: boolean; readonly creatorID: ID; constructor(public viewer: Viewer, protected data: Data) { - // @ts-ignore pass to mixin - super(viewer, data); this.id = data.id; this.createdAt = convertDate(data.created_at); this.updatedAt = convertDate(data.updated_at); + this.deletedAt = convertNullableDate(data.deleted_at); this.text = data.text; this.completed = convertBool(data.completed); this.creatorID = data.creator_id; diff --git a/examples/todo-sqlite/src/ent/internal.ts b/examples/todo-sqlite/src/ent/internal.ts index 92214cefd..a63db8353 100644 --- a/examples/todo-sqlite/src/ent/internal.ts +++ b/examples/todo-sqlite/src/ent/internal.ts @@ -2,7 +2,6 @@ export * from "src/ent/generated/const"; export * from "src/ent/generated/loaders"; -export * from "src/ent/generated/mixins/deleted_at"; export * from "src/ent/generated/account_base"; export * from "src/ent/generated/tag_base"; export * from "src/ent/generated/todo_base"; @@ -16,3 +15,7 @@ export * from "src/ent/account/query/account_to_tags_query"; export * from "src/ent/account/query/account_to_todos_query"; export * from "src/ent/tag/query/tag_to_todos_query"; export * from "src/ent/todo/query/todo_to_tags_query"; +import { setGlobalSchema } from "@snowtop/ent"; +import globalSchema from "src/schema/global_schema"; + +setGlobalSchema(globalSchema); diff --git a/examples/todo-sqlite/src/ent/tag/query/tag_to_todos_query.ts b/examples/todo-sqlite/src/ent/tag/query/tag_to_todos_query.ts index 9287db974..f0af54dab 100644 --- a/examples/todo-sqlite/src/ent/tag/query/tag_to_todos_query.ts +++ b/examples/todo-sqlite/src/ent/tag/query/tag_to_todos_query.ts @@ -1,5 +1,6 @@ -import { AssocEdge } from "@snowtop/ent"; +import { CustomTodoEdge } from "src/ent/edge/custom_edge"; import { TagToTodosQueryBase } from "src/ent/internal"; -export class TagToTodosEdge extends AssocEdge {} + +export class TagToTodosEdge extends CustomTodoEdge {} export class TagToTodosQuery extends TagToTodosQueryBase {} diff --git a/examples/todo-sqlite/src/ent/tests/todo.test.ts b/examples/todo-sqlite/src/ent/tests/todo.test.ts index ba031d8c4..6d94a5027 100644 --- a/examples/todo-sqlite/src/ent/tests/todo.test.ts +++ b/examples/todo-sqlite/src/ent/tests/todo.test.ts @@ -1,10 +1,14 @@ import ChangeTodoStatusAction from "src/ent/todo/actions/change_todo_status_action"; import RenameTodoStatusAction from "src/ent/todo/actions/rename_todo_status_action"; import DeleteTodoAction from "src/ent/todo/actions/delete_todo_action"; -import { Todo } from "src/ent/internal"; -import { createAccount, createTodo } from "../testutils/util"; +import { Todo, EdgeType } from "src/ent/"; +import { createAccount, createTag, createTodo } from "../testutils/util"; import { query } from "@snowtop/ent"; import { advanceTo } from "jest-date-mock"; +import TodoAddTagAction from "../todo/actions/todo_add_tag_action"; +import TodoRemoveTagAction from "../todo/actions/todo_remove_tag_action"; +import { loadCustomEdges } from "@snowtop/ent/core/ent"; +import { CustomTodoEdge } from "../edge/custom_edge"; test("create", async () => { await createTodo(); @@ -106,3 +110,49 @@ test("querying todos", async () => { }); expect(orderedOpenedTodos.length).toBe(3); }); + +test("tags", async () => { + const todo = await createTodo(); + const account = await todo.loadCreatorX(); + const tag = await createTag("sports", account); + const tag2 = await createTag("hello", account); + const tag3 = await createTag("exercise", account); + const tag4 = await createTag("fun", account); + + await TodoAddTagAction.create(todo.viewer, todo) + .addTag(tag) + .addTag(tag2) + .addTag(tag3) + .addTag(tag4) + .saveX(); + + const count = await todo.queryTags().queryRawCount(); + const tags = await todo.queryTags().queryEnts(); + const edges = await todo.queryTags().queryEdges(); + + expect(count).toBe(4); + expect(tags.length).toBe(4); + expect(edges.length).toBe(4); + expect(edges.every((edge) => edge.deletedAt === null)).toBe(true); + + await TodoRemoveTagAction.create(todo.viewer, todo).removeTag(tag).saveX(); + + const count2 = await todo.queryTags().queryRawCount(); + const tags2 = await todo.queryTags().queryEnts(); + const edges2 = await todo.queryTags().queryEdges(); + + expect(edges2.length).toBe(3); + expect(edges2.every((edge) => edge.deletedAt === null)).toBe(true); + expect(count2).toBe(3); + expect(tags2.length).toBe(3); + + // the deleted one is still in the db, just not returned by queries + const rawDB = await loadCustomEdges({ + edgeType: EdgeType.TodoToTags, + id1: todo.id, + ctr: CustomTodoEdge, + disableTransformations: true, + }); + expect(rawDB.length).toBe(4); + expect(rawDB.filter((edge) => edge.deletedAt !== null).length).toBe(1); +}); diff --git a/examples/todo-sqlite/src/ent/todo/query/todo_to_tags_query.ts b/examples/todo-sqlite/src/ent/todo/query/todo_to_tags_query.ts index 73d73847e..67a7c3152 100644 --- a/examples/todo-sqlite/src/ent/todo/query/todo_to_tags_query.ts +++ b/examples/todo-sqlite/src/ent/todo/query/todo_to_tags_query.ts @@ -1,5 +1,6 @@ -import { AssocEdge } from "@snowtop/ent"; +import { CustomTodoEdge } from "src/ent/edge/custom_edge"; import { TodoToTagsQueryBase } from "src/ent/internal"; -export class TodoToTagsEdge extends AssocEdge {} + +export class TodoToTagsEdge extends CustomTodoEdge {} export class TodoToTagsQuery extends TodoToTagsQueryBase {} diff --git a/examples/todo-sqlite/src/schema/global_schema.ts b/examples/todo-sqlite/src/schema/global_schema.ts new file mode 100644 index 000000000..42f185c6a --- /dev/null +++ b/examples/todo-sqlite/src/schema/global_schema.ts @@ -0,0 +1,7 @@ +import { GlobalSchema } from "@snowtop/ent/schema/"; +import { GlobalDeletedEdge } from "@snowtop/ent-soft-delete"; + +const glo: GlobalSchema = { + ...GlobalDeletedEdge, +}; +export default glo; diff --git a/examples/todo-sqlite/src/schema/schema.py b/examples/todo-sqlite/src/schema/schema.py index d7c1bbd9d..1d2c081cf 100644 --- a/examples/todo-sqlite/src/schema/schema.py +++ b/examples/todo-sqlite/src/schema/schema.py @@ -57,6 +57,7 @@ sa.Column("id2_type", sa.Text(), nullable=False), sa.Column("time", sa.TIMESTAMP(), nullable=False), sa.Column("data", sa.Text(), nullable=True), + sa.Column("deleted_at", sa.TIMESTAMP(), nullable=True), sa.PrimaryKeyConstraint("id1", "edge_type", "id2", name="todo_tags_edges_id1_edge_type_id2_pkey"), sa.Index("todo_tags_edges_time_idx", "time"), ) diff --git a/examples/todo-sqlite/src/schema/versions/28bc7ca6549d_202272863614_add_column_deleted_at_to_table_todo_.py b/examples/todo-sqlite/src/schema/versions/28bc7ca6549d_202272863614_add_column_deleted_at_to_table_todo_.py new file mode 100644 index 000000000..ed272868b --- /dev/null +++ b/examples/todo-sqlite/src/schema/versions/28bc7ca6549d_202272863614_add_column_deleted_at_to_table_todo_.py @@ -0,0 +1,32 @@ +# Code generated by github.com/lolopinto/ent/ent, DO NOT edit. + +"""add column deleted_at to table todo_tags_edges + +Revision ID: 28bc7ca6549d +Revises: 4c06d2c002d9 +Create Date: 2022-07-28 06:36:14.152011+00:00 + +""" +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects import postgresql + + +# revision identifiers, used by Alembic. +revision = '28bc7ca6549d' +down_revision = '4c06d2c002d9' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('todo_tags_edges', sa.Column( + 'deleted_at', sa.TIMESTAMP(), nullable=True)) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column('todo_tags_edges', 'deleted_at') + # ### end Alembic commands ### diff --git a/internal/codegen/codegenapi/api.go b/internal/codegen/codegenapi/api.go index 5d99b0b4b..06e6ef208 100644 --- a/internal/codegen/codegenapi/api.go +++ b/internal/codegen/codegenapi/api.go @@ -35,30 +35,30 @@ const ( OnDemand FieldPrivacyEvaluated = "on_demand" ) -type ViewerConfig struct { +type ImportedObject struct { Path string `yaml:"path"` Name string `yaml:"name"` Alias string `yaml:"alias"` } -func (cfg *ViewerConfig) Clone() *ViewerConfig { - return &ViewerConfig{ +func (cfg *ImportedObject) Clone() *ImportedObject { + return &ImportedObject{ Path: cfg.Path, Name: cfg.Name, Alias: cfg.Alias, } } -func (cfg *ViewerConfig) GetImport() string { +func (cfg *ImportedObject) GetImport() string { if cfg.Alias != "" { return cfg.Alias } return cfg.Name } -func (cfg *ViewerConfig) GetImportPath() *tsimport.ImportPath { +func (cfg *ImportedObject) GetImportPath() *tsimport.ImportPath { ret := &tsimport.ImportPath{ - ImportPath: cfg.Path, + ImportPath: strings.TrimSuffix(cfg.Path, ".ts"), Import: cfg.Name, } if cfg.Alias != "" { @@ -78,7 +78,8 @@ type Config interface { // doesn't actually writes the files, just keeps track of which files were going to be written // used to detect dangling files... DummyWrite() bool - GetTemplatizedViewer() *ViewerConfig + GetTemplatizedViewer() *ImportedObject + GetAssocEdgePath() *ImportedObject } // DummyConfig exists for tests/legacy paths which need Configs and don't want to create the production one @@ -109,13 +110,20 @@ func (cfg DummyConfig) DummyWrite() bool { return false } -func (cfg DummyConfig) GetTemplatizedViewer() *ViewerConfig { - return &ViewerConfig{ +func (cfg DummyConfig) GetTemplatizedViewer() *ImportedObject { + return &ImportedObject{ Path: codepath.Package, Name: "Viewer", } } +func (cfg DummyConfig) GetAssocEdgePath() *ImportedObject { + return &ImportedObject{ + Path: codepath.Package, + Name: "AssocEdge", + } +} + var _ Config = &DummyConfig{} func GraphQLName(cfg Config, name string) string { diff --git a/internal/codegen/config.go b/internal/codegen/config.go index 535baa306..cb4efb184 100644 --- a/internal/codegen/config.go +++ b/internal/codegen/config.go @@ -361,16 +361,35 @@ func (cfg *Config) FieldPrivacyEvaluated() codegenapi.FieldPrivacyEvaluated { return codegenapi.OnDemand } -func (cfg *Config) GetTemplatizedViewer() *codegenapi.ViewerConfig { +func (cfg *Config) GetTemplatizedViewer() *codegenapi.ImportedObject { if codegen := cfg.getCodegenConfig(); codegen != nil && codegen.TemplatizedViewer != nil { return codegen.TemplatizedViewer } - return &codegenapi.ViewerConfig{ + return &codegenapi.ImportedObject{ Path: codepath.Package, Name: "Viewer", } } +func (cfg *Config) GetAssocEdgePath() *codegenapi.ImportedObject { + if codegen := cfg.getCodegenConfig(); codegen != nil && codegen.CustomAssocEdgePath != nil { + return codegen.CustomAssocEdgePath + } + return &codegenapi.ImportedObject{ + Path: codepath.Package, + Name: "AssocEdge", + } +} + +func (cfg *Config) GetGlobalSchemaImportPath() string { + if cfg.config != nil { + if cfg.config.GlobalSchemaPath != "" { + return filepath.Join("src/schema", strings.Trim(cfg.config.GlobalSchemaPath, ".ts")) + } + } + return "src/schema/__global__schema" +} + const DEFAULT_GLOB = "src/**/*.ts" const PRETTIER_FILE_CHUNKS = 20 @@ -488,12 +507,14 @@ func parseConfig() (*config, error) { type config struct { Codegen *CodegenConfig `yaml:"codegen"` CustomGraphQLJSONPath string `yaml:"customGraphQLJSONPath"` + GlobalSchemaPath string `yaml:"globalSchemaPath"` } func (cfg *config) Clone() *config { return &config{ Codegen: cloneCodegen(cfg.Codegen), CustomGraphQLJSONPath: cfg.CustomGraphQLJSONPath, + GlobalSchemaPath: cfg.GlobalSchemaPath, } } @@ -518,7 +539,8 @@ type CodegenConfig struct { SchemaSQLFilePath string `yaml:"schemaSQLFilePath"` DatabaseToCompareTo string `yaml:"databaseToCompareTo"` FieldPrivacyEvaluated codegenapi.FieldPrivacyEvaluated `yaml:"fieldPrivacyEvaluated"` - TemplatizedViewer *codegenapi.ViewerConfig `yaml:"templatizedViewer"` + TemplatizedViewer *codegenapi.ImportedObject `yaml:"templatizedViewer"` + CustomAssocEdgePath *codegenapi.ImportedObject `yaml:"customAssocEdgePath"` } func cloneCodegen(cfg *CodegenConfig) *CodegenConfig { @@ -543,7 +565,8 @@ func (cfg *CodegenConfig) Clone() *CodegenConfig { SchemaSQLFilePath: cfg.SchemaSQLFilePath, DatabaseToCompareTo: cfg.DatabaseToCompareTo, FieldPrivacyEvaluated: cfg.FieldPrivacyEvaluated, - TemplatizedViewer: cloneViewerConfig(cfg.TemplatizedViewer), + TemplatizedViewer: cloneImportedObject(cfg.TemplatizedViewer), + CustomAssocEdgePath: cloneImportedObject(cfg.CustomAssocEdgePath), } } @@ -568,7 +591,7 @@ func (cfg *PrivacyConfig) Clone() *PrivacyConfig { } } -func cloneViewerConfig(cfg *codegenapi.ViewerConfig) *codegenapi.ViewerConfig { +func cloneImportedObject(cfg *codegenapi.ImportedObject) *codegenapi.ImportedObject { if cfg == nil { return nil } diff --git a/internal/db/db_schema.go b/internal/db/db_schema.go index 30f9d41f0..8de281996 100644 --- a/internal/db/db_schema.go +++ b/internal/db/db_schema.go @@ -511,10 +511,10 @@ func (s *dbSchema) processSchema(cfg *codegen.Config) error { func (s *dbSchema) generateShemaTables() error { - addedAtLeastOneTable := false + addedAtLeastOneEdgeTable := false for _, p := range s.schema.Patterns { if s.addEdgeTablesFromPattern(p) { - addedAtLeastOneTable = true + addedAtLeastOneEdgeTable = true } } for _, info := range s.schema.Nodes { @@ -522,7 +522,13 @@ func (s *dbSchema) generateShemaTables() error { s.addTable(s.getTableForNode(nodeData)) if s.addEdgeTables(nodeData) { - addedAtLeastOneTable = true + addedAtLeastOneEdgeTable = true + } + } + + for _, edge := range s.schema.GetGlobalEdges() { + if s.addEdgeTable(edge) { + addedAtLeastOneEdgeTable = true } } @@ -551,7 +557,7 @@ func (s *dbSchema) generateShemaTables() error { } } - if addedAtLeastOneTable { + if addedAtLeastOneEdgeTable { s.addEdgeConfigTable() } @@ -889,6 +895,10 @@ func (s *dbSchema) createEdgeTable(assocEdge *edge.AssociationEdge) *dbTable { }, } + for _, f := range s.schema.ExtraEdgeFields() { + columns = append(columns, s.getColumnInfoForFieldWithTable(f, tableName, &constraints)) + } + // add unique constraint for edge // TODO this only works when it's one table per edge // we need to add logic to deal with this @@ -911,6 +921,10 @@ func (s *dbSchema) createEdgeTable(assocEdge *edge.AssociationEdge) *dbTable { } func (s *dbSchema) getColumnInfoForField(f *field.Field, nodeData *schema.NodeData, constraints *[]dbConstraint) *dbColumn { + return s.getColumnInfoForFieldWithTable(f, nodeData.GetTableName(), constraints) +} + +func (s *dbSchema) getColumnInfoForFieldWithTable(f *field.Field, tableName string, constraints *[]dbConstraint) *dbColumn { dbType := f.GetDbTypeForField() var extraParts []string if f.Nullable() { @@ -924,7 +938,7 @@ func (s *dbSchema) getColumnInfoForField(f *field.Field, nodeData *schema.NodeDa col := s.getColumn(f.FieldName, f.GetDbColName(), dbType, extraParts) // index is still on a per field type so we leave this here - s.addIndexConstraint(f, nodeData, col, constraints) + s.addIndexConstraint(f, tableName, col, constraints) return col } @@ -1071,13 +1085,13 @@ func (s *dbSchema) addUniqueConstraint(nodeData *schema.NodeData, inputConstrain return nil } -func (s *dbSchema) addIndexConstraint(f *field.Field, nodeData *schema.NodeData, col *dbColumn, constraints *[]dbConstraint) { +func (s *dbSchema) addIndexConstraint(f *field.Field, tableName string, col *dbColumn, constraints *[]dbConstraint) { if !f.Index() { return } constraint := &indexConstraint{ dbColumns: []*dbColumn{col}, - tableName: nodeData.GetTableName(), + tableName: tableName, } // default index type for lists when not specified is gin type if enttype.IsListType(f.GetFieldType()) { diff --git a/internal/db/db_schema_test.go b/internal/db/db_schema_test.go index 9d194177f..e861195c4 100644 --- a/internal/db/db_schema_test.go +++ b/internal/db/db_schema_test.go @@ -2170,6 +2170,173 @@ func TestFullTextIndexMultipleColsGeneratedColumnMisMatchedWeights(t *testing.T) }) } +func TestGlobalEdge(t *testing.T) { + dbSchema := getSchemaFromInput( + t, + &input.Schema{ + Nodes: map[string]*input.Node{ + "User": { + Fields: []*input.Field{ + { + Name: "id", + Type: &input.FieldType{ + DBType: input.UUID, + }, + PrimaryKey: true, + }, + }, + }, + }, + GlobalSchema: &input.GlobalSchema{ + GlobalEdges: []*input.AssocEdge{ + { + Name: "external_info", + SchemaName: "User", + }, + { + Name: "external_info_on_wheels", + SchemaName: "User", + }, + }, + }, + }, + ) + + require.Len(t, dbSchema.tableMap, 4) + expTables := []string{ + "assoc_edge_config", + "users", + "global_external_info_edges", + "global_external_info_on_wheels_edges", + } + for _, tbl := range expTables { + table := dbSchema.tableMap[tbl] + require.NotNil(t, table) + + if tbl == "global_external_info_edges" || tbl == "global_external_info_on_wheels_edges" { + testEdgeTable(t, table) + } + } +} + +func TestGlobalEdgeWithInverse(t *testing.T) { + dbSchema := getSchemaFromInput( + t, + &input.Schema{ + Nodes: map[string]*input.Node{ + "User": { + Fields: []*input.Field{ + { + Name: "id", + Type: &input.FieldType{ + DBType: input.UUID, + }, + PrimaryKey: true, + }, + }, + }, + }, + GlobalSchema: &input.GlobalSchema{ + GlobalEdges: []*input.AssocEdge{ + { + Name: "external_info", + SchemaName: "User", + InverseEdge: &input.InverseAssocEdge{ + Name: "user_external_info", + }, + }, + }, + }, + }, + ) + + require.Len(t, dbSchema.tableMap, 3) + expTables := []string{ + "assoc_edge_config", + "users", + "global_external_info_edges", + } + for _, tbl := range expTables { + table := dbSchema.tableMap[tbl] + require.NotNil(t, table) + + if tbl == "global_external_info_edges" { + testEdgeTable(t, table) + } + } +} + +func TestExtraEdgeCols(t *testing.T) { + dbSchema := getSchemaFromInput( + t, + &input.Schema{ + Nodes: map[string]*input.Node{ + "User": { + Fields: []*input.Field{ + { + Name: "id", + Type: &input.FieldType{ + DBType: input.UUID, + }, + PrimaryKey: true, + }, + }, + AssocEdges: []*input.AssocEdge{ + { + Name: "friends", + SchemaName: "User", + }, + }, + }, + }, + GlobalSchema: &input.GlobalSchema{ + ExtraEdgeFields: []*input.Field{ + { + Name: "deleted_at", + Type: &input.FieldType{ + DBType: input.Timestamp, + }, + }, + }, + GlobalEdges: []*input.AssocEdge{ + { + Name: "external_info", + SchemaName: "User", + InverseEdge: &input.InverseAssocEdge{ + Name: "user_external_info", + }, + }, + }, + }, + }, + ) + + require.Len(t, dbSchema.tableMap, 4) + expTables := []string{ + "assoc_edge_config", + "users", + "user_friends_edges", + "global_external_info_edges", + } + for _, tbl := range expTables { + table := dbSchema.tableMap[tbl] + require.NotNil(t, table) + + if tbl == "global_external_info_edges" || tbl == "user_friends_edges" { + testEdgeTable(t, table) + + found := false + for _, col := range table.Columns { + if col.DBColName == "deleted_at" { + found = true + break + } + } + assert.True(t, found, "couldn't find deleted_at column") + } + } +} + func TestExplicitIndexBtree(t *testing.T) { dbSchema := getSchemaFromInput( t, @@ -2373,7 +2540,7 @@ func getSchemaFromInput(t *testing.T, s *input.Schema) *dbSchema { } func testEdgeTable(t *testing.T, table *dbTable) { - assert.Equal(t, 7, len(table.Columns), "invalid number of columns for table generated. expected %d, got %d", 7, len(table.Columns)) + assert.GreaterOrEqual(t, len(table.Columns), 7, "invalid number of columns for table generated. expected at least %d, got %d", 7, len(table.Columns)) // 1 primary key constraint for the id1, edge_type, id2 fields assert.GreaterOrEqual( diff --git a/internal/edge/edge.go b/internal/edge/edge.go index 228086e49..9a1a31e29 100644 --- a/internal/edge/edge.go +++ b/internal/edge/edge.go @@ -764,11 +764,11 @@ func (e *AssociationEdge) EdgeQueryBase() string { return e.TsEdgeQueryName() + "Base" } -func (e *AssociationEdge) AssocEdgeBase() string { +func (e *AssociationEdge) AssocEdgeBaseImport(cfg codegenapi.Config) *tsimport.ImportPath { if e.patternEdgeConst != "" { - return fmt.Sprintf("%sEdge", e.patternEdgeConst) + return tsimport.NewEntImportPath(fmt.Sprintf("%sEdge", e.patternEdgeConst)) } - return "AssocEdge" + return cfg.GetAssocEdgePath().GetImportPath() } func (e *AssociationEdge) PolymorphicEdge() bool { diff --git a/internal/graphql/ts_templates/connection.tmpl b/internal/graphql/ts_templates/connection.tmpl index b2dbd4a95..d6a11f619 100644 --- a/internal/graphql/ts_templates/connection.tmpl +++ b/internal/graphql/ts_templates/connection.tmpl @@ -1,5 +1,5 @@ {{reserveImport "graphql" "GraphQLSchema" "GraphQLObjectType" "GraphQLInputObjectType" "GraphQLID" "GraphQLString" "GraphQLEnumType" "GraphQLNonNull" "GraphQLList" "GraphQLFloat" "GraphQLInt" "GraphQLFieldConfig" "GraphQLFieldConfigMap" "GraphQLResolveInfo" "GraphQLInputFieldConfigMap" "GraphQLBoolean" }} -{{reserveImport .Package.PackagePath "ID" "RequestContext" "AssocEdge"}} +{{reserveImport .Package.PackagePath "ID" "RequestContext" }} {{reserveImport .Package.GraphQLPackagePath "GraphQLTime" "GraphQLEdgeType" "GraphQLConnectionType" "GraphQLEdge" "GraphQLNodeInterface"}} {{$conn := .Connection}} {{$baseObj := .BaseObj}} diff --git a/internal/schema/input/input.go b/internal/schema/input/input.go index 428279300..e3941c282 100644 --- a/internal/schema/input/input.go +++ b/internal/schema/input/input.go @@ -14,8 +14,9 @@ import ( ) type Schema struct { - Nodes map[string]*Node `json:"schemas,omitempty"` - Patterns map[string]*Pattern `json:"patterns,omitempty"` + Nodes map[string]*Node `json:"schemas,omitempty"` + Patterns map[string]*Pattern `json:"patterns,omitempty"` + GlobalSchema *GlobalSchema `json:"globalSchema"` } type Pattern struct { @@ -58,6 +59,12 @@ func (n *Node) AddAssocEdgeGroup(edgeGroup *AssocEdgeGroup) { n.AssocEdgeGroups = append(n.AssocEdgeGroups, edgeGroup) } +type GlobalSchema struct { + ExtraEdgeFields []*Field `json:"extraEdgeFields,omitempty"` + GlobalEdges []*AssocEdge `json:"globalEdges,omitempty"` + InitForEdges bool `json:"initForEdges,omitempty"` +} + type DBType string const ( diff --git a/internal/schema/obj_with_consts.go b/internal/schema/obj_with_consts.go index 7c38dd75f..5bcbe65e9 100644 --- a/internal/schema/obj_with_consts.go +++ b/internal/schema/obj_with_consts.go @@ -59,3 +59,9 @@ func (obj *objWithConsts) GetSortedConstantGroups() []*ConstGroupInfo { return sorted } + +func (obj *objWithConsts) GetNodeInstance() string { + // would be ideal to have a default value used here so comments for global edges + // don't look weird. not high pri + return "" +} diff --git a/internal/schema/schema.go b/internal/schema/schema.go index a722e763c..884bc2af2 100644 --- a/internal/schema/schema.go +++ b/internal/schema/schema.go @@ -29,12 +29,16 @@ import ( // Schema is the representation of the parsed schema. Has everything needed to type Schema struct { - Nodes NodeMapInfo - Patterns map[string]*PatternInfo - tables NodeMapInfo - edges map[string]*ent.AssocEdgeData - newEdges []*ent.AssocEdgeData - edgesToUpdate []*ent.AssocEdgeData + Nodes NodeMapInfo + Patterns map[string]*PatternInfo + globalEdges []*edge.AssociationEdge + globalConsts *objWithConsts + extraEdgeFields []*field.Field + initForEdges bool + tables NodeMapInfo + edges map[string]*ent.AssocEdgeData + newEdges []*ent.AssocEdgeData + edgesToUpdate []*ent.AssocEdgeData // unlike Nodes, the key is "EnumName" instead of "EnumNameConfig" // confusing but gets us closer to what we want Enums map[string]*EnumInfo @@ -50,6 +54,22 @@ func (s *Schema) GetInputSchema() *input.Schema { return s.inputSchema } +func (s *Schema) GetGlobalEdges() []*edge.AssociationEdge { + return s.globalEdges +} + +func (s *Schema) InitForEdges() bool { + return s.initForEdges +} + +func (s *Schema) ExtraEdgeFields() []*field.Field { + return s.extraEdgeFields +} + +func (s *Schema) GetGlobalConsts() WithConst { + return s.globalConsts +} + func (s *Schema) addEnum(enumType enttype.EnumeratedType, nodeData *NodeData) error { return s.addEnumFrom( enum.NewInputFromEnumType(enumType), @@ -267,6 +287,7 @@ func (s *Schema) init() { s.Patterns = map[string]*PatternInfo{} s.CustomInterfaces = map[string]*customtype.CustomInterface{} s.gqlNameMap = make(map[string]bool) + s.globalConsts = &objWithConsts{} } func (s *Schema) GetNodeDataFromTableName(tableName string) *NodeData { @@ -462,7 +483,7 @@ func (s *Schema) parseInputSchema(cfg codegenapi.Config, schema *input.Schema, l if err := s.addConfig(&NodeDataInfo{ NodeData: nodeData, - depgraph: s.buildPostRunDepgraph(cfg, edgeData), + depgraph: s.buildPostRunDepgraph(cfg), ShouldCodegen: true, }); err != nil { errs = append(errs, err) @@ -543,6 +564,10 @@ func (s *Schema) parseInputSchema(cfg codegenapi.Config, schema *input.Schema, l } } + if schema.GlobalSchema != nil { + errs = append(errs, s.parseGlobalSchema(cfg, schema.GlobalSchema, edgeData)...) + } + // TODO convert more things to do something like this? if len(errs) > 0 { // we're getting list of errors and coalescing @@ -552,6 +577,43 @@ func (s *Schema) parseInputSchema(cfg codegenapi.Config, schema *input.Schema, l return s.processDepgrah(edgeData) } +func (s *Schema) parseGlobalSchema(cfg codegenapi.Config, gs *input.GlobalSchema, edgeData *assocEdgeData) []error { + var errs []error + for _, inputEdge := range gs.GlobalEdges { + assocEdge, err := edge.AssocEdgeFromInput(cfg, "global", inputEdge) + if err != nil { + errs = append(errs, err) + } else { + s.globalEdges = append(s.globalEdges, assocEdge) + if assocEdge.CreateEdge() { + newEdge, err := s.getNewEdge(edgeData, assocEdge) + if err != nil { + errs = append(errs, err) + } else { + s.addNewEdgeType(s.globalConsts, newEdge.constName, newEdge.constValue, assocEdge) + } + if err := s.maybeAddInverseAssocEdge(assocEdge); err != nil { + errs = append(errs, err) + } + } + } + } + + if len(gs.ExtraEdgeFields) > 0 { + fi, err := field.NewFieldInfoFromInputs(cfg, "global", gs.ExtraEdgeFields, &field.Options{ + SortFields: true, + }) + if err != nil { + errs = append(errs, err) + } + s.extraEdgeFields = fi.Fields + } + + s.initForEdges = gs.InitForEdges + + return errs +} + func (s *Schema) validateIndices(nodeData *NodeData) error { verifyCols := func(cols []string, getError func(col string) error) error { for _, col := range cols { @@ -830,7 +892,6 @@ func (s *Schema) addConfig(info *NodeDataInfo) error { func (s *Schema) buildPostRunDepgraph( cfg codegenapi.Config, - edgeData *assocEdgeData, ) *depgraph.Depgraph { // things that need all nodeDatas loaded g := &depgraph.Depgraph{} diff --git a/internal/schema/schema_global_schema_test.go b/internal/schema/schema_global_schema_test.go new file mode 100644 index 000000000..edbb78589 --- /dev/null +++ b/internal/schema/schema_global_schema_test.go @@ -0,0 +1,163 @@ +package schema_test + +import ( + "testing" + + "github.com/lolopinto/ent/internal/schema/base" + "github.com/lolopinto/ent/internal/schema/input" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestGlobalEdge(t *testing.T) { + inputSchema := &input.Schema{ + Nodes: map[string]*input.Node{ + "User": { + Fields: []*input.Field{ + { + Name: "id", + Type: &input.FieldType{ + DBType: input.UUID, + }, + PrimaryKey: true, + }, + }, + }, + }, + GlobalSchema: &input.GlobalSchema{ + GlobalEdges: []*input.AssocEdge{ + { + Name: "external_info", + SchemaName: "User", + }, + { + Name: "external_info_on_wheels", + SchemaName: "User", + }, + }, + }, + } + schema, err := parseFromInputSchema(inputSchema, base.TypeScript) + require.Nil(t, err) + assert.Len(t, schema.Nodes, 1) + + edges := schema.GetGlobalEdges() + require.Len(t, edges, 2) + + consts := schema.GetGlobalConsts() + groups := consts.GetConstantGroups() + require.Len(t, groups, 1) + + edgeConsts := groups["ent.EdgeType"] + require.Len(t, edgeConsts.Constants, 2) + + require.NotNil(t, edgeConsts.Constants["GlobalToExternalInfoOnWheelsEdge"]) + require.NotNil(t, edgeConsts.Constants["GlobalToExternalInfoEdge"]) +} + +func TestGlobalEdgeWithInverse(t *testing.T) { + inputSchema := &input.Schema{ + Nodes: map[string]*input.Node{ + "User": { + Fields: []*input.Field{ + { + Name: "id", + Type: &input.FieldType{ + DBType: input.UUID, + }, + PrimaryKey: true, + }, + }, + }, + }, + GlobalSchema: &input.GlobalSchema{ + GlobalEdges: []*input.AssocEdge{ + { + Name: "external_info", + SchemaName: "User", + InverseEdge: &input.InverseAssocEdge{ + Name: "user_external_info", + }, + }, + }, + }, + } + + schema, err := parseFromInputSchema(inputSchema, base.TypeScript) + require.Nil(t, err) + assert.Len(t, schema.Nodes, 1) + + edges := schema.GetGlobalEdges() + require.Len(t, edges, 1) + + consts := schema.GetGlobalConsts() + groups := consts.GetConstantGroups() + require.Len(t, groups, 1) + + edgeConsts := groups["ent.EdgeType"] + require.Len(t, edgeConsts.Constants, 1) + + require.NotNil(t, edgeConsts.Constants["GlobalToExternalInfoEdge"]) + + user := schema.Nodes["UserConfig"] + userGroups := user.NodeData.GetConstantGroups() + require.Len(t, userGroups, 2) + + useEdgeConsts := userGroups["ent.EdgeType"] + require.Len(t, useEdgeConsts.Constants, 1) + + require.NotNil(t, useEdgeConsts.Constants["UserToUserExternalInfoEdge"]) +} + +func TestExtraEdgeCols(t *testing.T) { + inputSchema := &input.Schema{ + Nodes: map[string]*input.Node{ + "User": { + Fields: []*input.Field{ + { + Name: "id", + Type: &input.FieldType{ + DBType: input.UUID, + }, + PrimaryKey: true, + }, + }, + AssocEdges: []*input.AssocEdge{ + { + Name: "friends", + SchemaName: "User", + }, + }, + }, + }, + GlobalSchema: &input.GlobalSchema{ + ExtraEdgeFields: []*input.Field{ + { + Name: "deleted_at", + Type: &input.FieldType{ + DBType: input.Timestamp, + }, + }, + }, + GlobalEdges: []*input.AssocEdge{ + { + Name: "external_info", + SchemaName: "User", + InverseEdge: &input.InverseAssocEdge{ + Name: "user_external_info", + }, + }, + }, + }, + } + + schema, err := parseFromInputSchema(inputSchema, base.TypeScript) + require.Nil(t, err) + assert.Len(t, schema.Nodes, 1) + + extraFields := schema.ExtraEdgeFields() + require.Len(t, extraFields, 1) + require.Equal(t, extraFields[0].FieldName, "deleted_at") +} + +// TODO AssocEdgeBaseImport test based on what we do in ent.yml?? diff --git a/internal/schema/schema_go.go b/internal/schema/schema_go.go index 3f4a6a187..c235ef3b0 100644 --- a/internal/schema/schema_go.go +++ b/internal/schema/schema_go.go @@ -78,7 +78,7 @@ func (s *Schema) parseFile( g := &depgraph.Depgraph{} // things that need all nodeDatas loaded - g2 := s.buildPostRunDepgraph(&codegenapi.DummyConfig{}, edgeData) + g2 := s.buildPostRunDepgraph(&codegenapi.DummyConfig{}) var shouldCodegen bool diff --git a/internal/schema/schema_input_test.go b/internal/schema/schema_input_test.go index b08574d7f..a9cc2b5cf 100644 --- a/internal/schema/schema_input_test.go +++ b/internal/schema/schema_input_test.go @@ -1125,7 +1125,7 @@ func TestWithPatterns(t *testing.T) { require.NotNil(t, likesEdge) assert.Len(t, userCfg.NodeData.EdgeInfo.Associations, 1) assert.Equal(t, "UserToLikedObjects", likesEdge.TsEdgeConst) - assert.Equal(t, "AssocEdge", likesEdge.AssocEdgeBase()) + assert.Equal(t, "AssocEdge", likesEdge.AssocEdgeBaseImport(&codegenapi.DummyConfig{}).Import) assert.Equal(t, "UserToLikedObjectsQueryBase", likesEdge.EdgeQueryBase()) assert.Equal(t, "UserToLikedObjectsEdge", likesEdge.TsEdgeQueryEdgeName()) assert.Equal(t, "UserToLikedObjectsQuery", likesEdge.TsEdgeQueryName()) @@ -1139,7 +1139,7 @@ func TestWithPatterns(t *testing.T) { require.NotNil(t, likersEdge) assert.Len(t, postCfg.NodeData.EdgeInfo.Associations, 1) assert.Equal(t, "LikedPostToLikers", likersEdge.TsEdgeConst) - assert.Equal(t, "LikedPostToLikersEdge", likersEdge.AssocEdgeBase()) + assert.Equal(t, "LikedPostToLikersEdge", likersEdge.AssocEdgeBaseImport(&codegenapi.DummyConfig{}).Import) assert.Equal(t, "LikedPostToLikersQuery", likersEdge.EdgeQueryBase()) assert.Equal(t, "PostToLikersEdge", likersEdge.TsEdgeQueryEdgeName()) assert.Equal(t, "PostToLikersQuery", likersEdge.TsEdgeQueryName()) @@ -1153,7 +1153,7 @@ func TestWithPatterns(t *testing.T) { require.NotNil(t, likersEdge2) assert.Len(t, groupCfg.NodeData.EdgeInfo.Associations, 1) assert.Equal(t, "LikedPostToLikers", likersEdge2.TsEdgeConst) - assert.Equal(t, "LikedPostToLikersEdge", likersEdge2.AssocEdgeBase()) + assert.Equal(t, "LikedPostToLikersEdge", likersEdge2.AssocEdgeBaseImport(&codegenapi.DummyConfig{}).Import) assert.Equal(t, "LikedPostToLikersQuery", likersEdge2.EdgeQueryBase()) assert.Equal(t, "GroupToLikersEdge", likersEdge2.TsEdgeQueryEdgeName()) assert.Equal(t, "GroupToLikersQuery", likersEdge2.TsEdgeQueryName()) @@ -1169,7 +1169,7 @@ func TestWithPatterns(t *testing.T) { patternLikersEdge := likersPattern.AssocEdges["likers"] require.NotNil(t, patternLikersEdge) assert.Equal(t, "LikedPostToLikers", patternLikersEdge.TsEdgeConst) - assert.Equal(t, "AssocEdge", patternLikersEdge.AssocEdgeBase()) + assert.Equal(t, "AssocEdge", patternLikersEdge.AssocEdgeBaseImport(&codegenapi.DummyConfig{}).Import) assert.Equal(t, "LikedPostToLikersQueryBase", patternLikersEdge.EdgeQueryBase()) assert.Equal(t, "LikedPostToLikersEdge", patternLikersEdge.TsEdgeQueryEdgeName()) assert.Equal(t, "LikedPostToLikersQuery", patternLikersEdge.TsEdgeQueryName()) @@ -1372,7 +1372,7 @@ func TestWithPatternsNoEdgeConstName(t *testing.T) { require.NotNil(t, likesEdge) assert.Len(t, userCfg.NodeData.EdgeInfo.Associations, 1) assert.Equal(t, "UserToLikes", likesEdge.TsEdgeConst) - assert.Equal(t, "AssocEdge", likesEdge.AssocEdgeBase()) + assert.Equal(t, "AssocEdge", likesEdge.AssocEdgeBaseImport(&codegenapi.DummyConfig{}).Import) assert.Equal(t, "UserToLikesQueryBase", likesEdge.EdgeQueryBase()) assert.Equal(t, "UserToLikesEdge", likesEdge.TsEdgeQueryEdgeName()) assert.Equal(t, "UserToLikesQuery", likesEdge.TsEdgeQueryName()) @@ -1387,7 +1387,7 @@ func TestWithPatternsNoEdgeConstName(t *testing.T) { assert.Len(t, postCfg.NodeData.EdgeInfo.Associations, 1) // these 3 are wrong and lead to codegen issues assert.Equal(t, "ObjectToLikers", likersEdge.TsEdgeConst) - assert.Equal(t, "ObjectToLikersEdge", likersEdge.AssocEdgeBase()) + assert.Equal(t, "ObjectToLikersEdge", likersEdge.AssocEdgeBaseImport(&codegenapi.DummyConfig{}).Import) assert.Equal(t, "ObjectToLikersQuery", likersEdge.EdgeQueryBase()) assert.Equal(t, "PostToLikersEdge", likersEdge.TsEdgeQueryEdgeName()) assert.Equal(t, "PostToLikersQuery", likersEdge.TsEdgeQueryName()) @@ -1401,7 +1401,7 @@ func TestWithPatternsNoEdgeConstName(t *testing.T) { require.NotNil(t, likersEdge2) assert.Len(t, groupCfg.NodeData.EdgeInfo.Associations, 1) assert.Equal(t, "ObjectToLikers", likersEdge2.TsEdgeConst) - assert.Equal(t, "ObjectToLikersEdge", likersEdge2.AssocEdgeBase()) + assert.Equal(t, "ObjectToLikersEdge", likersEdge2.AssocEdgeBaseImport(&codegenapi.DummyConfig{}).Import) assert.Equal(t, "ObjectToLikersQuery", likersEdge2.EdgeQueryBase()) assert.Equal(t, "GroupToLikersEdge", likersEdge2.TsEdgeQueryEdgeName()) assert.Equal(t, "GroupToLikersQuery", likersEdge2.TsEdgeQueryName()) @@ -1417,7 +1417,7 @@ func TestWithPatternsNoEdgeConstName(t *testing.T) { patternLikersEdge := likersPattern.AssocEdges["likers"] require.NotNil(t, patternLikersEdge) assert.Equal(t, "ObjectToLikers", patternLikersEdge.TsEdgeConst) - assert.Equal(t, "AssocEdge", patternLikersEdge.AssocEdgeBase()) + assert.Equal(t, "AssocEdge", patternLikersEdge.AssocEdgeBaseImport(&codegenapi.DummyConfig{}).Import) assert.Equal(t, "ObjectToLikersQueryBase", patternLikersEdge.EdgeQueryBase()) assert.Equal(t, "ObjectToLikersEdge", patternLikersEdge.TsEdgeQueryEdgeName()) assert.Equal(t, "ObjectToLikersQuery", patternLikersEdge.TsEdgeQueryName()) diff --git a/internal/tscode/assoc_ent_query.tmpl b/internal/tscode/assoc_ent_query.tmpl index bf2648775..4895b83eb 100644 --- a/internal/tscode/assoc_ent_query.tmpl +++ b/internal/tscode/assoc_ent_query.tmpl @@ -2,16 +2,12 @@ {{$name := .Edge.TsEdgeQueryName -}} {{$base := .Edge.EdgeQueryBase -}} +{{ $cfg := .Config}} {{ reserveImport .Package.InternalImportPath $base $edgeName -}} -{{ $assocEdgeBase := .Edge.AssocEdgeBase -}} -{{/* TODO this should be generalized eventually but it's either a base class or AssocEdge so it's fine for now */ -}} -{{ if eq $assocEdgeBase "AssocEdge" -}} - {{ reserveImport .Package.PackagePath "AssocEdge" -}} -{{ else -}} - {{ reserveImport "src/ent/internal" $assocEdgeBase -}} -{{ end -}} +{{ $assocEdgeBase := .Edge.AssocEdgeBaseImport $cfg -}} +{{ reserveImportPath $assocEdgeBase false }} -export class {{$edgeName}} extends {{useImport $assocEdgeBase}} {} +export class {{$edgeName}} extends {{useImport $assocEdgeBase.Import}} {} {{ if eq .SourceNode "Ent" -}} export abstract class {{$name}} extends {{useImport $base}} { diff --git a/internal/tscode/base.tmpl b/internal/tscode/base.tmpl index 1e69dcb08..e10fd3bee 100644 --- a/internal/tscode/base.tmpl +++ b/internal/tscode/base.tmpl @@ -1,4 +1,4 @@ -{{ reserveImport .Package.PackagePath "loadEnt" "ID" "Data" "loadEntX" "loadEnts" "LoadEntOptions" "AssocEdge" "loadNodesByEdge" "loadRow" "loadRows" "loadRowX" "loadUniqueEdge" "loadUniqueNode" "AllowIfViewerPrivacyPolicy" "PrivacyPolicy" "query" "Ent" "getEdgeTypeInGroup" "ObjectLoaderFactory" "Context" "IndexLoaderFactory" "loadEntViaKey" "loadEntXViaKey" "CustomQuery" "loadCustomEnts" "loadCustomData" "applyPrivacyPolicy" "Ent"}} +{{ reserveImport .Package.PackagePath "loadEnt" "ID" "Data" "loadEntX" "loadEnts" "LoadEntOptions" "loadNodesByEdge" "loadRow" "loadRows" "loadRowX" "loadUniqueEdge" "loadUniqueNode" "AllowIfViewerPrivacyPolicy" "PrivacyPolicy" "query" "Ent" "getEdgeTypeInGroup" "ObjectLoaderFactory" "Context" "IndexLoaderFactory" "loadEntViaKey" "loadEntXViaKey" "CustomQuery" "loadCustomEnts" "loadCustomData" "applyPrivacyPolicy" "Ent"}} {{ reserveImport .Package.SchemaPackagePath "Field" "getFields" "getFieldsWithPrivacy"}} {{ reserveImport .Package.InternalImportPath "EdgeType" "NodeType" }} {{ reserveImport "src/ent/generated/loadAny" "loadEntByType" "loadEntXByType"}} @@ -401,7 +401,9 @@ implements {{useImport "Ent"}}<{{$viewerType}}> {{$uniqueEdge := .Unique -}} {{with .NodeInfo -}} {{ if $uniqueEdge -}} - {{$assocEdgeType := useImport "AssocEdge"}} + {{ $imp := $edge.AssocEdgeBaseImport $cfg}} + {{ reserveImportPath $imp false }} + {{$assocEdgeType := useImport $imp.Import }} {{$edgeType := useImport "EdgeType"}} load{{$edgeName}}Edge(): Promise<{{$assocEdgeType}} | null> { return {{useImport "loadUniqueEdge"}}({ diff --git a/internal/tscode/custom_interface.tmpl b/internal/tscode/custom_interface.tmpl index 0bc22bfb6..68fec1e42 100644 --- a/internal/tscode/custom_interface.tmpl +++ b/internal/tscode/custom_interface.tmpl @@ -1,4 +1,4 @@ -{{ reserveImport .Package.PackagePath "loadEnt" "ID" "Data" "Viewer" "loadEntX" "loadEnts" "LoadEntOptions" "AssocEdge" "loadNodesByEdge" "loadRow" "loadRows" "loadRowX" "loadUniqueEdge" "loadUniqueNode" "AllowIfViewerPrivacyPolicy" "PrivacyPolicy" "query" "Ent" "getEdgeTypeInGroup" "ObjectLoaderFactory" "Context" "IndexLoaderFactory" "loadEntViaKey" "loadEntXViaKey" "CustomQuery" "loadCustomEnts" "loadCustomData"}} +{{ reserveImport .Package.PackagePath "loadEnt" "ID" "Data" "Viewer" "loadEntX" "loadEnts" "LoadEntOptions" "loadNodesByEdge" "loadRow" "loadRows" "loadRowX" "loadUniqueEdge" "loadUniqueNode" "AllowIfViewerPrivacyPolicy" "PrivacyPolicy" "query" "Ent" "getEdgeTypeInGroup" "ObjectLoaderFactory" "Context" "IndexLoaderFactory" "loadEntViaKey" "loadEntXViaKey" "CustomQuery" "loadCustomEnts" "loadCustomData"}} {{ $ci := .Interface}} {{ $pkg := .Package }} diff --git a/internal/tscode/ent_query_base.tmpl b/internal/tscode/ent_query_base.tmpl index c854a39c0..d855b9936 100644 --- a/internal/tscode/ent_query_base.tmpl +++ b/internal/tscode/ent_query_base.tmpl @@ -1,5 +1,5 @@ {{ reserveImport .Package.InternalImportPath "EdgeType" "NodeType" }} -{{ reserveImport .Package.PackagePath "Ent" "ID" "Data" "Viewer" "EdgeQuerySource" "BaseEdgeQuery" "AssocEdge" "AssocEdgeQueryBase" "CustomEdgeQueryBase" "query" "RawCountLoaderFactory" "AssocEdgeCountLoaderFactory" "AssocEdgeLoaderFactory" "IndexLoaderFactory" "loadEnt" "LoadEntOptions"}} +{{ reserveImport .Package.PackagePath "Ent" "ID" "Data" "Viewer" "EdgeQuerySource" "BaseEdgeQuery" "AssocEdgeQueryBase" "CustomEdgeQueryBase" "query" "RawCountLoaderFactory" "AssocEdgeCountLoaderFactory" "AssocEdgeLoaderFactory" "IndexLoaderFactory" "loadEnt" "LoadEntOptions"}} {{$importPath := .Package.InternalImportPath -}} {{reserveImport "src/ent/generated/loadAny" "getLoaderOptions" -}} {{ reserveImport .Package.SchemaPackagePath "getTransformedReadClause" }} diff --git a/internal/tscode/internal.tmpl b/internal/tscode/internal.tmpl index eb62f7d88..401062564 100644 --- a/internal/tscode/internal.tmpl +++ b/internal/tscode/internal.tmpl @@ -1,3 +1,9 @@ -{{range . -}} +{{range .SortedLines -}} {{exportAll .}} -{{end -}} \ No newline at end of file +{{end -}} + +{{ if .Schema.InitForEdges -}} + {{reserveImport .Package.PackagePath "setGlobalSchema"}} + {{ reserveDefaultImport .Config.GetGlobalSchemaImportPath "globalSchema"}} + {{ useImport "setGlobalSchema"}}({{useImport "globalSchema"}}); +{{ end -}} diff --git a/internal/tscode/mixin.tmpl b/internal/tscode/mixin.tmpl index fff41c7df..fef96eb94 100644 --- a/internal/tscode/mixin.tmpl +++ b/internal/tscode/mixin.tmpl @@ -1,4 +1,4 @@ -{{ reserveImport .Package.PackagePath "loadEnt" "ID" "Data" "loadEntX" "loadEnts" "LoadEntOptions" "AssocEdge" "loadNodesByEdge" "loadRow" "loadRows" "loadRowX" "loadUniqueEdge" "loadUniqueNode" "AllowIfViewerPrivacyPolicy" "PrivacyPolicy" "query" "Ent" "getEdgeTypeInGroup" "ObjectLoaderFactory" "Context" "IndexLoaderFactory" "loadEntViaKey" "loadEntXViaKey" "CustomQuery" "loadCustomEnts" "loadCustomData" "applyPrivacyPolicy" "Ent" "Viewer" "Data"}} +{{ reserveImport .Package.PackagePath "loadEnt" "ID" "Data" "loadEntX" "loadEnts" "LoadEntOptions" "loadNodesByEdge" "loadRow" "loadRows" "loadRowX" "loadUniqueEdge" "loadUniqueNode" "AllowIfViewerPrivacyPolicy" "PrivacyPolicy" "query" "Ent" "getEdgeTypeInGroup" "ObjectLoaderFactory" "Context" "IndexLoaderFactory" "loadEntViaKey" "loadEntXViaKey" "CustomQuery" "loadCustomEnts" "loadCustomData" "applyPrivacyPolicy" "Ent" "Viewer" "Data"}} {{$p := .Pattern}} {{$cfg := .Config}} diff --git a/internal/tscode/mixin_builder.tmpl b/internal/tscode/mixin_builder.tmpl index 261d99e41..31bf91d96 100644 --- a/internal/tscode/mixin_builder.tmpl +++ b/internal/tscode/mixin_builder.tmpl @@ -1,4 +1,4 @@ -{{ reserveImport .Package.PackagePath "loadEnt" "ID" "Data" "loadEntX" "loadEnts" "LoadEntOptions" "AssocEdge" "loadNodesByEdge" "loadRow" "loadRows" "loadRowX" "loadUniqueEdge" "loadUniqueNode" "AllowIfViewerPrivacyPolicy" "PrivacyPolicy" "query" "Ent" "getEdgeTypeInGroup" "ObjectLoaderFactory" "Context" "IndexLoaderFactory" "loadEntViaKey" "loadEntXViaKey" "CustomQuery" "loadCustomEnts" "loadCustomData" "applyPrivacyPolicy" "Ent" "Viewer" "Data" "AssocEdgeInputOptions" }} +{{ reserveImport .Package.PackagePath "loadEnt" "ID" "Data" "loadEntX" "loadEnts" "LoadEntOptions" "loadNodesByEdge" "loadRow" "loadRows" "loadRowX" "loadUniqueEdge" "loadUniqueNode" "AllowIfViewerPrivacyPolicy" "PrivacyPolicy" "query" "Ent" "getEdgeTypeInGroup" "ObjectLoaderFactory" "Context" "IndexLoaderFactory" "loadEntViaKey" "loadEntXViaKey" "CustomQuery" "loadCustomEnts" "loadCustomData" "applyPrivacyPolicy" "Ent" "Viewer" "Data" "AssocEdgeInputOptions" }} {{reserveImport .Package.ActionPackagePath "Action" "Builder" "WriteOperation" "Changeset" "saveBuilder" "saveBuilderX" "Orchestrator"}} {{$p := .Pattern}} diff --git a/internal/tscode/step.go b/internal/tscode/step.go index a12a00540..15e8ac906 100644 --- a/internal/tscode/step.go +++ b/internal/tscode/step.go @@ -439,6 +439,10 @@ func (s *Step) ProcessData(processor *codegen.Processor) error { } } + if err := s.accumulateConsts(processor.Schema.GetGlobalConsts()); err != nil { + serr.Append(err) + } + for k := range processor.Schema.Enums { info := processor.Schema.Enums[k] if !info.OwnEnumFile() { @@ -857,10 +861,12 @@ func writeAssocEdgeQueryFile(processor *codegen.Processor, e *edge.AssociationEd Edge *edge.AssociationEdge Package *codegen.ImportPackage SourceNode string + Config *codegen.Config }{ Edge: e, Package: cfg.GetImportPackage(), SourceNode: sourceNode, + Config: cfg, }, AbsPathToTemplate: util.GetAbsolutePath("assoc_ent_query.tmpl"), TemplateName: "assoc_ent_query.tmpl", @@ -1123,8 +1129,18 @@ func writeInternalEntFile(s *schema.Schema, processor *codegen.Processor) error imps := tsimport.NewImports(processor.Config, path) return file.Write(&file.TemplatedBasedFileWriter{ - Config: processor.Config, - Data: getSortedInternalEntFileLines(s), + Config: processor.Config, + Data: struct { + SortedLines []string + Schema *schema.Schema + Config *codegen.Config + Package *codegen.ImportPackage + }{ + getSortedInternalEntFileLines(s), + s, + processor.Config, + cfg.GetImportPackage(), + }, AbsPathToTemplate: util.GetAbsolutePath("internal.tmpl"), TemplateName: "internal.tmpl", PathToFile: path, diff --git a/ts/package.json b/ts/package.json index 46c3f7d77..ea51765ab 100644 --- a/ts/package.json +++ b/ts/package.json @@ -1,6 +1,6 @@ { "name": "@snowtop/ent", - "version": "0.1.0-alpha56", + "version": "0.1.0-alpha58", "description": "snowtop ent framework", "main": "index.js", "types": "index.d.ts", diff --git a/ts/packages/ent-soft-delete/package-lock.json b/ts/packages/ent-soft-delete/package-lock.json index 6eeed02cf..eb36fa258 100644 --- a/ts/packages/ent-soft-delete/package-lock.json +++ b/ts/packages/ent-soft-delete/package-lock.json @@ -1,24 +1,24 @@ { "name": "@snowtop/ent-soft-delete", - "version": "0.1.0-alpha1", + "version": "0.1.0-alpha2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@snowtop/ent-soft-delete", - "version": "0.1.0-alpha1", + "version": "0.1.0-alpha2", "license": "ISC", "dependencies": { "@types/express": "^4.17.13" }, "devDependencies": { - "@snowtop/ent": "^0.1.0-alpha20", + "@snowtop/ent": "^0.1.0-alpha55", "@types/jest": "^26.0.23", "jest": "^26.6.3", "ts-jest": "^26.5.6" }, "peerDependencies": { - "@snowtop/ent": ">= 0.1.0-alpha20" + "@snowtop/ent": ">= 0.1.0-alpha55" } }, "node_modules/@babel/code-frame": { @@ -922,9 +922,9 @@ } }, "node_modules/@snowtop/ent": { - "version": "0.1.0-alpha20", - "resolved": "https://registry.npmjs.org/@snowtop/ent/-/ent-0.1.0-alpha20.tgz", - "integrity": "sha512-1J4a1rWupMpZUUJp9iEL+WScWJrUf3aDBZDboSy1J/hvARw2R+5dqAVVseVdsCF+kajs+MjIL+GXh8hVO8kZtA==", + "version": "0.1.0-alpha55", + "resolved": "https://registry.npmjs.org/@snowtop/ent/-/ent-0.1.0-alpha55.tgz", + "integrity": "sha512-L0tI3r2YARhfiOkUMRCzTBISuoZU4Xji7/+Z/huLxLKMDN/KV2UL9OFNgcxns7JFNKaIRF70ciRK2QjuEgNveQ==", "dev": true, "dependencies": { "@types/node": "^15.0.2", @@ -8209,9 +8209,9 @@ } }, "@snowtop/ent": { - "version": "0.1.0-alpha20", - "resolved": "https://registry.npmjs.org/@snowtop/ent/-/ent-0.1.0-alpha20.tgz", - "integrity": "sha512-1J4a1rWupMpZUUJp9iEL+WScWJrUf3aDBZDboSy1J/hvARw2R+5dqAVVseVdsCF+kajs+MjIL+GXh8hVO8kZtA==", + "version": "0.1.0-alpha55", + "resolved": "https://registry.npmjs.org/@snowtop/ent/-/ent-0.1.0-alpha55.tgz", + "integrity": "sha512-L0tI3r2YARhfiOkUMRCzTBISuoZU4Xji7/+Z/huLxLKMDN/KV2UL9OFNgcxns7JFNKaIRF70ciRK2QjuEgNveQ==", "dev": true, "requires": { "@types/node": "^15.0.2", diff --git a/ts/packages/ent-soft-delete/package.json b/ts/packages/ent-soft-delete/package.json index d9d4cc6f9..95cee9701 100644 --- a/ts/packages/ent-soft-delete/package.json +++ b/ts/packages/ent-soft-delete/package.json @@ -1,6 +1,6 @@ { "name": "@snowtop/ent-soft-delete", - "version": "0.1.0-alpha1", + "version": "0.1.0-alpha3", "description": "snowtop ent soft delete", "main": "dist/soft_delete.js", "types": "dist/soft_delete.d.ts", @@ -29,13 +29,13 @@ }, "homepage": "https://github.com/lolopinto/ent#readme", "devDependencies": { - "@snowtop/ent": "^0.1.0-alpha20", + "@snowtop/ent": "^0.1.0-alpha55", "@types/jest": "^26.0.23", "jest": "^26.6.3", "ts-jest": "^26.5.6" }, "peerDependencies": { - "@snowtop/ent": ">= 0.1.0-alpha20" + "@snowtop/ent": ">= 0.1.0-alpha55" }, "dependencies": { "@types/express": "^4.17.13" diff --git a/ts/packages/ent-soft-delete/src/soft_delete.ts b/ts/packages/ent-soft-delete/src/soft_delete.ts index 6cbbcba29..f51cfec32 100644 --- a/ts/packages/ent-soft-delete/src/soft_delete.ts +++ b/ts/packages/ent-soft-delete/src/soft_delete.ts @@ -1,11 +1,13 @@ import { Pattern, TimestampType, - Field, Ent, UpdateOperation, TransformedUpdateOperation, SQLStatementOperation, + FieldMap, + EdgeUpdateOperation, + TransformedEdgeUpdateOperation, } from "@snowtop/ent"; import * as clause from "@snowtop/ent/core/clause"; @@ -14,16 +16,15 @@ export class DeletedAtPattern implements Pattern { disableMixin = true; - fields: Field[] = [ - TimestampType({ - name: "deleted_at", + fields: FieldMap = { + deleted_at: TimestampType({ nullable: true, index: true, defaultValueOnCreate: () => null, hideFromGraphQL: true, private: true, }), - ]; + }; transformRead(): clause.Clause { return clause.Eq("deleted_at", null); @@ -37,7 +38,6 @@ export class DeletedAtPattern implements Pattern { return { op: SQLStatementOperation.Update, data: { - // this should return field, it'll be formatted as needed deleted_at: new Date(), }, }; @@ -47,3 +47,31 @@ export class DeletedAtPattern implements Pattern { transformsDelete = true; } + +export const GlobalDeletedEdge = { + extraEdgeFields: { + deleted_at: TimestampType({ + nullable: true, + defaultValueOnCreate: () => null, + }), + }, + + transformEdgeRead(): clause.Clause { + return clause.Eq("deleted_at", null); + }, + + transformEdgeWrite( + stmt: EdgeUpdateOperation, + ): TransformedEdgeUpdateOperation | null { + switch (stmt.op) { + case SQLStatementOperation.Delete: + return { + op: SQLStatementOperation.Update, + data: { + deleted_at: new Date(), + }, + }; + } + return null; + }, +}; diff --git a/ts/src/action/action.test.ts b/ts/src/action/action.test.ts index 7a4efba86..6d759a9eb 100644 --- a/ts/src/action/action.test.ts +++ b/ts/src/action/action.test.ts @@ -11,6 +11,9 @@ import { buildUpdateQuery, loadEdgeForID2, assocEdgeLoader, + setGlobalSchema, + clearGlobalSchema, + __hasGlobalSchema, } from "../core/ent"; import { setEdgeTypeInGroup, WriteOperation } from "./action"; import { MockLogs } from "../testutils/mock_log"; @@ -22,9 +25,10 @@ import { setupSqlite, table, text, -} from "../testutils/db/test_db"; +} from "../testutils/db/temp_db"; import DB, { Dialect } from "../core/db"; import * as clause from "../core/clause"; +import { testEdgeGlobalSchema } from "../testutils/test_edge_global_schema"; jest.mock("pg"); QueryRecorder.mockPool(Pool); @@ -55,7 +59,22 @@ describe("postgres", () => { ml.clear(); QueryRecorder.clear(); }); - commonTests(); + + describe("with global schema", () => { + beforeAll(() => { + setGlobalSchema(testEdgeGlobalSchema); + }); + + afterAll(() => { + clearGlobalSchema(); + }); + + commonTests(); + }); + + describe("without global schema", () => { + commonTests(); + }); }); describe("sqlite", () => { @@ -71,21 +90,40 @@ describe("sqlite", () => { QueryRecorder.clear(); ml.clear(); }); - setupSqlite(`sqlite:///action-test.db`, () => [ - table( - "users", - // uuid field goes here - text("id", { primaryKey: true }), - text("foo"), - ), - assoc_edge_config_table(), - assoc_edge_table("edge_table"), - assoc_edge_table("edge1_table"), - assoc_edge_table("edge2_table"), - assoc_edge_table("edge3_table"), - ]); - - commonTests(); + + function getTables(global = false) { + return [ + table( + "users", + // uuid field goes here + text("id", { primaryKey: true }), + text("foo"), + ), + assoc_edge_config_table(), + assoc_edge_table("edge_table", global), + assoc_edge_table("edge1_table", global), + assoc_edge_table("edge2_table", global), + assoc_edge_table("edge3_table", global), + ]; + } + + describe("with global schema", () => { + beforeAll(() => { + setGlobalSchema(testEdgeGlobalSchema); + }); + + afterAll(() => { + clearGlobalSchema(); + }); + + setupSqlite(`sqlite:///action-test-global.db`, () => getTables(true)); + commonTests(); + }); + + describe("without global schema", () => { + setupSqlite(`sqlite:///action-test.db`, () => getTables()); + commonTests(); + }); }); class UserSchema implements BuilderSchema { @@ -132,7 +170,6 @@ function getInsertQuery(id: ID) { function getUpdateQuery(ent: User) { const [query, _, logValues] = buildUpdateQuery( { - key: "id", tableName: "users", fields: { foo: "bar", @@ -140,8 +177,8 @@ function getUpdateQuery(ent: User) { fieldsToLog: { foo: "bar", }, + whereClause: clause.Eq("id", ent.id), }, - ent.id, "RETURNING *", ); return { query, values: logValues }; @@ -250,7 +287,8 @@ function commonTests() { // select for sqlite - const fields = { + const global = __hasGlobalSchema(); + const fields: Data = { id1: ent.id, id2: id2, id1_type: "User", @@ -259,13 +297,18 @@ function commonTests() { data: null, time: date.toISOString(), }; + if (global) { + fields.deleted_at = null; + } const [query, _, logValues] = buildInsertQuery( { tableName: "edge_table", fields: fields, fieldsToLog: fields, }, - "ON CONFLICT(id1, edge_type, id2) DO UPDATE SET data = EXCLUDED.data", + global + ? "ON CONFLICT(id1, edge_type, id2) DO UPDATE SET data = EXCLUDED.data, deleted_at = EXCLUDED.deleted_at" + : "ON CONFLICT(id1, edge_type, id2) DO UPDATE SET data = EXCLUDED.data", ); expect(ml.logs[lastIdx]).toEqual({ query: query, @@ -301,7 +344,7 @@ function commonTests() { expect(ml.logs[0].query).toMatch(/SELECT (.+) FROM assoc_edge_config/); expect(ml.logs[1]).toEqual(getUpdateQuery(ent)); - const fields = { + const fields: Data = { id1: ent.id, id2: id2, id1_type: "User", @@ -310,13 +353,20 @@ function commonTests() { data: null, time: date.toISOString(), }; + const global = __hasGlobalSchema(); + if (global) { + fields.deleted_at = null; + } + const [query, _, logValues] = buildInsertQuery( { tableName: "edge_table", fields: fields, fieldsToLog: fields, }, - "ON CONFLICT(id1, edge_type, id2) DO UPDATE SET data = EXCLUDED.data", + global + ? "ON CONFLICT(id1, edge_type, id2) DO UPDATE SET data = EXCLUDED.data, deleted_at = EXCLUDED.deleted_at" + : "ON CONFLICT(id1, edge_type, id2) DO UPDATE SET data = EXCLUDED.data", ); expect(ml.logs[lastIdx]).toEqual({ query: query, diff --git a/ts/src/action/executor.test.ts b/ts/src/action/executor.test.ts index a2691fb9b..54d125905 100644 --- a/ts/src/action/executor.test.ts +++ b/ts/src/action/executor.test.ts @@ -51,7 +51,7 @@ import { getSchemaTable, setupSqlite, Table, -} from "../testutils/db/test_db"; +} from "../testutils/db/temp_db"; import * as action from "../action"; jest.mock("pg"); @@ -109,86 +109,6 @@ afterEach(() => { operations = []; }); -describe("postgres", () => { - commonTests(); -}); - -describe("sqlite", () => { - const getTables = () => { - const tables: Table[] = [assoc_edge_config_table()]; - edges.map((edge) => tables.push(assoc_edge_table(`${edge}_table`))); - - [ - AccountSchema, - ContactSchema, - GroupSchema, - UserSchema, - MessageSchema, - GroupMembershipSchema, - ChangelogSchema, - ].map((s) => tables.push(getSchemaTable(s, Dialect.SQLite))); - return tables; - }; - - setupSqlite(`sqlite:///executor-test.db`, getTables); - commonTests(); -}); - -jest.spyOn(action, "saveBuilder").mockImplementation(saveBuilder); -jest.spyOn(action, "saveBuilderX").mockImplementation(saveBuilderX); - -async function saveBuilder(builder: Builder): Promise { - const changeset = await builder.build(); - const executor = changeset.executor(); - operations = await executeOperations(executor, builder.viewer.context, true); -} - -async function saveBuilderX(builder: Builder): Promise { - return saveBuilder(builder); -} - -async function executeAction( - action: Action>, - name?: E, -): Promise { - const exec = await executor(action.builder); - if (name !== undefined) { - expect(exec).toBeInstanceOf(name); - } - operations = await executeOperations( - exec, - action.builder.viewer.context, - true, - ); - return exec; -} - -async function executor(builder: Builder): Promise { - const changeset = await builder.build(); - return changeset.executor(); -} - -async function createGroup() { - let groupID = QueryRecorder.newID(); - let groupFields = { - id: groupID, - name: "group", - created_at: new Date(), - updated_at: new Date(), - }; - // need to create the group first - await createRowForTest({ - tableName: "groups", - fields: groupFields, - }); - return new Group(new LoggedOutViewer(), groupFields); -} - -async function createUser(): Promise { - const id = QueryRecorder.newID(); - return new User(new IDViewer(id), { id }); -} - const UserSchema = getBuilderSchemaFromFields( { FirstName: StringType(), @@ -284,6 +204,86 @@ const MessageSchema = getBuilderSchemaFromFields( Message, ); +describe("postgres", () => { + commonTests(); +}); + +describe("sqlite", () => { + const getTables = () => { + const tables: Table[] = [assoc_edge_config_table()]; + edges.map((edge) => tables.push(assoc_edge_table(`${edge}_table`))); + + [ + AccountSchema, + ContactSchema, + GroupSchema, + UserSchema, + MessageSchema, + GroupMembershipSchema, + ChangelogSchema, + ].map((s) => tables.push(getSchemaTable(s, Dialect.SQLite))); + return tables; + }; + + setupSqlite(`sqlite:///executor-test.db`, getTables); + commonTests(); +}); + +jest.spyOn(action, "saveBuilder").mockImplementation(saveBuilder); +jest.spyOn(action, "saveBuilderX").mockImplementation(saveBuilderX); + +async function saveBuilder(builder: Builder): Promise { + const changeset = await builder.build(); + const executor = changeset.executor(); + operations = await executeOperations(executor, builder.viewer.context, true); +} + +async function saveBuilderX(builder: Builder): Promise { + return saveBuilder(builder); +} + +async function executeAction( + action: Action>, + name?: E, +): Promise { + const exec = await executor(action.builder); + if (name !== undefined) { + expect(exec).toBeInstanceOf(name); + } + operations = await executeOperations( + exec, + action.builder.viewer.context, + true, + ); + return exec; +} + +async function executor(builder: Builder): Promise { + const changeset = await builder.build(); + return changeset.executor(); +} + +async function createGroup() { + let groupID = QueryRecorder.newID(); + let groupFields = { + id: groupID, + name: "group", + created_at: new Date(), + updated_at: new Date(), + }; + // need to create the group first + await createRowForTest({ + tableName: "groups", + fields: groupFields, + }); + return new Group(new LoggedOutViewer(), groupFields); +} + +async function createUser(): Promise { + const id = QueryRecorder.newID(); + return new User(new IDViewer(id), { id }); +} + class MessageAction extends SimpleAction { constructor( viewer: Viewer, diff --git a/ts/src/action/orchestrator.test.ts b/ts/src/action/orchestrator.test.ts index 7b0a5e95a..a97b6c3b5 100644 --- a/ts/src/action/orchestrator.test.ts +++ b/ts/src/action/orchestrator.test.ts @@ -12,8 +12,6 @@ import { DeleteNodeOperation, DataOperation, EdgeOperation, - loadEdges, - loadRow, loadRows, } from "../core/ent"; import { LoggedOutViewer, IDViewer } from "../core/viewer"; @@ -47,7 +45,6 @@ import { DenyIfLoggedOutRule, AllowIfEntPropertyIsRule, } from "../core/privacy"; -import { edgeDirection } from "./orchestrator"; import { createRowForTest } from "../testutils/write"; import * as clause from "../core/clause"; import { snakeCase } from "snake-case"; @@ -60,9 +57,9 @@ import { getSchemaTable, setupSqlite, Table, -} from "../testutils/db/test_db"; +} from "../testutils/db/temp_db"; import { Dialect } from "../core/db"; -import { convertList } from "../core/convert"; +import { convertDate, convertList } from "../core/convert"; import { v4 } from "uuid"; jest.mock("pg"); @@ -92,41 +89,6 @@ afterEach(() => { FakeComms.clear(); }); -describe("postgres", () => { - commonTests(); -}); - -describe("sqlite", () => { - const getTables = () => { - const tables: Table[] = [assoc_edge_config_table()]; - edges.map((edge) => - tables.push(assoc_edge_table(`${snakeCase(edge)}_table`)), - ); - - [ - UserSchema, - UserSchemaWithStatus, - UserSchemaExtended, - UserSchemaServerDefault, - UserSchemaDefaultValueOnCreate, - UserSchemaDefaultValueOnCreateJSON, - UserSchemaDefaultValueOnCreateInvalidJSON, - SchemaWithProcessors, - EventSchema, - AddressSchemaDerivedFields, - ContactSchema, - ContactSchema3, - CustomUserSchema, - ContactEmailSchema, - SensitiveValuesSchema, - ].map((s) => tables.push(getSchemaTable(s, Dialect.SQLite))); - return tables; - }; - - setupSqlite(`sqlite:///orchestrator-test.db`, getTables); - commonTests(); -}); - const UserSchema = getBuilderSchemaFromFields( { FirstName: StringType(), @@ -332,6 +294,54 @@ const SensitiveValuesSchema = getBuilderSchemaFromFields( SensitiveUser, ); +class NullableEvent extends Event {} + +const SchemaWithNullFields = getBuilderSchemaFromFields( + { + startTime: TimestampType(), + endTime: TimestampType({ + nullable: true, + }), + }, + NullableEvent, +); + +describe("postgres", () => { + commonTests(); +}); + +describe("sqlite", () => { + const getTables = () => { + const tables: Table[] = [assoc_edge_config_table()]; + edges.map((edge) => + tables.push(assoc_edge_table(`${snakeCase(edge)}_table`)), + ); + + [ + UserSchema, + UserSchemaWithStatus, + UserSchemaExtended, + UserSchemaServerDefault, + UserSchemaDefaultValueOnCreate, + UserSchemaDefaultValueOnCreateJSON, + UserSchemaDefaultValueOnCreateInvalidJSON, + SchemaWithProcessors, + EventSchema, + AddressSchemaDerivedFields, + ContactSchema, + ContactSchema3, + CustomUserSchema, + ContactEmailSchema, + SensitiveValuesSchema, + SchemaWithNullFields, + ].map((s) => tables.push(getSchemaTable(s, Dialect.SQLite))); + return tables; + }; + + setupSqlite(`sqlite:///orchestrator-test.db`, getTables); + commonTests(); +}); + function getInsertUserAction( map: Map, viewer: Viewer = new LoggedOutViewer(), @@ -519,14 +529,6 @@ function commonTests() { }); test("schema with null fields", async () => { - const SchemaWithNullFields = getBuilderSchemaFromFields( - { - startTime: TimestampType(), - endTime: TimestampType({ nullable: true }), - }, - User, - ); - const d = new Date(); const builder = new SimpleBuilder( new LoggedOutViewer(), @@ -542,12 +544,20 @@ function commonTests() { validateFieldsExist(fields, "id", "created_at", "updated_at"); validateFieldsDoNotExist(fields, "end_time"); + await builder.saveX(); + const evt = await builder.editedEntX(); + expect(convertDate(evt.data.start_time).toISOString()).toBe( + d.toISOString(), + ); + // undefined in fake postgres, null in sqlite + expect(evt.data.end_time).toBeFalsy(); + const builder2 = new SimpleBuilder( new LoggedOutViewer(), SchemaWithNullFields, new Map([ ["startTime", d], - ["endTime", null], + ["endTime", d], ]), WriteOperation.Insert, null, @@ -557,6 +567,28 @@ function commonTests() { expect(fields2["start_time"]).toEqual(d.toISOString()); validateFieldsExist(fields2, "id", "created_at", "updated_at"); + + await builder2.saveX(); + const evt2 = await builder2.editedEntX(); + expect(convertDate(evt2.data.start_time).toISOString()).toBe( + d.toISOString(), + ); + expect(convertDate(evt2.data.end_time).toISOString()).toBe(d.toISOString()); + + const builder3 = new SimpleBuilder( + new LoggedOutViewer(), + SchemaWithNullFields, + new Map([["endTime", null]]), + WriteOperation.Edit, + evt2, + ); + + await builder3.saveX(); + const evt3 = await builder3.editedEntX(); + expect(convertDate(evt3.data.start_time).toISOString()).toBe( + d.toISOString(), + ); + expect(evt3.data.end_time).toBeNull(); }); test("schema_with_overriden_storage_key", async () => { @@ -655,1147 +687,6 @@ function commonTests() { }); }); - describe("inbound edge", () => { - test("no options", async () => { - const builder = getLoggedInBuilder(); - builder.orchestrator.addInboundEdge("2", "edge", "User"); - - expect( - builder.orchestrator.getInputEdges("edge", WriteOperation.Insert), - ).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - id: "2", - edgeType: "edge", - nodeType: "User", - direction: edgeDirection.inboundEdge, - }), - ]), - ); - expect( - builder.orchestrator.getInputEdges("edge", WriteOperation.Delete), - ).toEqual([]); - - const edgeOp = await getEdgeOpFromBuilder(builder, 3, "edge"); - expect(edgeOp.edgeInput).toStrictEqual({ - id1: "2", - id1Type: "User", - edgeType: "edge", - id2: "1", - id2Type: "User", - }); - }); - - test("no id. creating. no options", async () => { - const builder = getCreateBuilder( - new Map([ - ["FirstName", "Jon"], - ["LastName", "Snow"], - ]), - ); - builder.orchestrator.addInboundEdge("2", "edge", "User"); - - expect( - builder.orchestrator.getInputEdges("edge", WriteOperation.Insert), - ).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - id: "2", - edgeType: "edge", - nodeType: "User", - direction: edgeDirection.inboundEdge, - }), - ]), - ); - expect( - builder.orchestrator.getInputEdges("edge", WriteOperation.Delete), - ).toEqual([]); - - const edgeOp = await getEdgeOpFromBuilder(builder, 3, "edge"); - expect(edgeOp.edgeInput).toStrictEqual({ - id1: "2", - id1Type: "User", - edgeType: "edge", - id2: builder.placeholderID, - id2Type: "", - }); - }); - - test("no options then add options", async () => { - const builder = getLoggedInBuilder(); - builder.orchestrator.addInboundEdge("2", "edge", "User"); - - expect( - builder.orchestrator.getInputEdges("edge", WriteOperation.Insert), - ).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - id: "2", - edgeType: "edge", - nodeType: "User", - direction: edgeDirection.inboundEdge, - }), - ]), - ); - expect( - builder.orchestrator.getInputEdges("edge", WriteOperation.Delete), - ).toEqual([]); - - builder.orchestrator.addInboundEdge("2", "edge", "User", { - data: "123456", - }); - expect( - builder.orchestrator.getInputEdges("edge", WriteOperation.Insert), - ).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - id: "2", - edgeType: "edge", - nodeType: "User", - direction: edgeDirection.inboundEdge, - options: { - data: "123456", - }, - }), - ]), - ); - expect( - builder.orchestrator.getInputEdges("edge", WriteOperation.Delete), - ).toEqual([]); - - const edgeOp = await getEdgeOpFromBuilder(builder, 3, "edge"); - expect(edgeOp.edgeInput).toStrictEqual({ - id1: "2", - id1Type: "User", - edgeType: "edge", - id2: "1", - id2Type: "User", - data: "123456", - }); - }); - - test("no id. creating. no options, then add options", async () => { - const builder = getCreateBuilder( - new Map([ - ["FirstName", "Jon"], - ["LastName", "Snow"], - ]), - ); - builder.orchestrator.addInboundEdge("2", "edge", "User"); - - expect( - builder.orchestrator.getInputEdges("edge", WriteOperation.Insert), - ).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - id: "2", - edgeType: "edge", - nodeType: "User", - direction: edgeDirection.inboundEdge, - }), - ]), - ); - expect( - builder.orchestrator.getInputEdges("edge", WriteOperation.Delete), - ).toEqual([]); - - builder.orchestrator.addInboundEdge("2", "edge", "User", { - data: "123456", - }); - expect( - builder.orchestrator.getInputEdges("edge", WriteOperation.Insert), - ).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - id: "2", - edgeType: "edge", - nodeType: "User", - direction: edgeDirection.inboundEdge, - options: { - data: "123456", - }, - }), - ]), - ); - expect( - builder.orchestrator.getInputEdges("edge", WriteOperation.Delete), - ).toEqual([]); - - const edgeOp = await getEdgeOpFromBuilder(builder, 3, "edge"); - expect(edgeOp.edgeInput).toStrictEqual({ - id1: "2", - id1Type: "User", - edgeType: "edge", - id2: builder.placeholderID, - id2Type: "", - data: "123456", - }); - }); - - test("options then diff options", async () => { - const builder = getLoggedInBuilder(); - builder.orchestrator.addInboundEdge("2", "edge", "User", { - data: "123456", - }); - - expect( - builder.orchestrator.getInputEdges("edge", WriteOperation.Insert), - ).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - id: "2", - edgeType: "edge", - nodeType: "User", - direction: edgeDirection.inboundEdge, - options: { - data: "123456", - }, - }), - ]), - ); - expect( - builder.orchestrator.getInputEdges("edge", WriteOperation.Delete), - ).toEqual([]); - - let date = new Date(); - builder.orchestrator.addInboundEdge("2", "edge", "User", { - data: "123456", - time: date, - }); - expect( - builder.orchestrator.getInputEdges("edge", WriteOperation.Insert), - ).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - id: "2", - edgeType: "edge", - nodeType: "User", - direction: edgeDirection.inboundEdge, - options: { - data: "123456", - time: date, - }, - }), - ]), - ); - expect( - builder.orchestrator.getInputEdges("edge", WriteOperation.Delete), - ).toEqual([]); - - const edgeOp = await getEdgeOpFromBuilder(builder, 3, "edge"); - expect(edgeOp.edgeInput).toStrictEqual({ - id1: "2", - id1Type: "User", - edgeType: "edge", - id2: "1", - id2Type: "User", - data: "123456", - time: date, - }); - }); - - test("no id. creating. options, then diff options", async () => { - const builder = getCreateBuilder( - new Map([ - ["FirstName", "Jon"], - ["LastName", "Snow"], - ]), - ); - builder.orchestrator.addInboundEdge("2", "edge", "User", { - data: "123456", - }); - - expect( - builder.orchestrator.getInputEdges("edge", WriteOperation.Insert), - ).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - id: "2", - edgeType: "edge", - nodeType: "User", - direction: edgeDirection.inboundEdge, - options: { - data: "123456", - }, - }), - ]), - ); - expect( - builder.orchestrator.getInputEdges("edge", WriteOperation.Delete), - ).toEqual([]); - - // NOTE: data wasn't set in re-adding so it's removed... - let date = new Date(); - builder.orchestrator.addInboundEdge("2", "edge", "User", { - time: date, - }); - expect( - builder.orchestrator.getInputEdges("edge", WriteOperation.Insert), - ).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - id: "2", - edgeType: "edge", - nodeType: "User", - direction: edgeDirection.inboundEdge, - options: { - time: date, - }, - }), - ]), - ); - expect( - builder.orchestrator.getInputEdges("edge", WriteOperation.Delete), - ).toEqual([]); - - const edgeOp = await getEdgeOpFromBuilder(builder, 3, "edge"); - expect(edgeOp.edgeInput).toStrictEqual({ - id1: "2", - id1Type: "User", - edgeType: "edge", - id2: builder.placeholderID, - id2Type: "", - time: date, - }); - }); - - test("id in data field with placeholder", async () => { - // create user1 - const user = await createUser( - new Map([ - ["FirstName", "Arya"], - ["LastName", "Stark"], - ]), - ); - - const action = getInsertUserAction( - new Map([ - ["FirstName", "Jon"], - ["LastName", "Snow"], - ]), - ); - action.builder.orchestrator.addInboundEdge(user.id, "edge", "User"); - action.getTriggers = () => [ - { - changeset: (builder: SimpleBuilder) => { - const derivedAction = getInsertUserAction( - new Map([ - ["FirstName", "Sansa"], - ["LastName", "Stark"], - ]), - ); - - // take the edges and write it as 3 edge - const edges = builder.orchestrator.getInputEdges( - "edge", - WriteOperation.Insert, - ); - edges.forEach((edge) => { - builder.orchestrator.addInboundEdge( - edge.id, - edge.edgeType, - edge.nodeType!, - { - data: derivedAction.builder, - }, - ); - }); - - return derivedAction.changeset(); - }, - }, - ]; - - const newUser = await action.saveX(); - expect(newUser).toBeInstanceOf(User); - if (!newUser) { - throw new Error("impossible"); - } - - const edges = await loadEdges({ - id1: user.id, - edgeType: "edge", - }); - expect(edges.length).toBe(1); - const edge = edges[0]; - expect(edge.id1).toBe(user.id); - expect(edge.id2).toBe(newUser.id); - expect(edge.data).not.toBeNull(); - - // we were able to resolve the id correctly and then set it as needed - const sansaData = await loadRow({ - tableName: "users", - fields: ["first_name", "last_name"], - clause: clause.Eq("id", edge.data), - }); - expect(sansaData).toBeDefined(); - expect(sansaData?.first_name).toBe("Sansa"); - expect(sansaData?.last_name).toBe("Stark"); - - const inverseEdges = await loadEdges({ - id1: newUser.id, - edgeType: "inverseEdge", - }); - expect(inverseEdges.length).toBe(1); - expect(inverseEdges[0].data).toBe(edge.data); - }); - - test("id in data field symmetric edge", async () => { - // create user1 - const user = await createUser( - new Map([ - ["FirstName", "Arya"], - ["LastName", "Stark"], - ]), - ); - - const action = getInsertUserAction( - new Map([ - ["FirstName", "Jon"], - ["LastName", "Snow"], - ]), - ); - action.builder.orchestrator.addInboundEdge( - user.id, - "symmetricEdge", - "User", - ); - action.getTriggers = () => [ - { - changeset: (builder: SimpleBuilder) => { - const derivedAction = getInsertUserAction( - new Map([ - ["FirstName", "Sansa"], - ["LastName", "Stark"], - ]), - ); - - // take the edges and write it as 3 edge - const edges = builder.orchestrator.getInputEdges( - "symmetricEdge", - WriteOperation.Insert, - ); - edges.forEach((edge) => { - builder.orchestrator.addInboundEdge( - edge.id, - edge.edgeType, - edge.nodeType!, - { - data: derivedAction.builder, - }, - ); - }); - - return derivedAction.changeset(); - }, - }, - ]; - - const newUser = await action.saveX(); - expect(newUser).toBeInstanceOf(User); - if (!newUser) { - throw new Error("impossible"); - } - - const edges = await loadEdges({ - id1: user.id, - edgeType: "symmetricEdge", - }); - expect(edges.length).toBe(1); - const edge = edges[0]; - expect(edge.id1).toBe(user.id); - expect(edge.id2).toBe(newUser.id); - expect(edge.data).not.toBeNull(); - - // we were able to resolve the id correctly and then set it as needed - const sansaData = await loadRow({ - tableName: "users", - fields: ["first_name", "last_name"], - clause: clause.Eq("id", edge.data), - }); - expect(sansaData).toBeDefined(); - expect(sansaData?.first_name).toBe("Sansa"); - expect(sansaData?.last_name).toBe("Stark"); - - const inverseEdges = await loadEdges({ - id1: newUser.id, - edgeType: "symmetricEdge", - }); - expect(inverseEdges.length).toBe(1); - expect(inverseEdges[0].data).toBe(edge.data); - }); - }); - - describe("outbound edge", () => { - test("no options", async () => { - const builder = getLoggedInBuilder(); - builder.orchestrator.addOutboundEdge("2", "edge", "User"); - - expect( - builder.orchestrator.getInputEdges("edge", WriteOperation.Insert), - ).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - id: "2", - edgeType: "edge", - nodeType: "User", - direction: edgeDirection.outboundEdge, - }), - ]), - ); - expect( - builder.orchestrator.getInputEdges("edge", WriteOperation.Delete), - ).toEqual([]); - - // 3 ops, edit, outbound, inverse - const edgeOp = await getEdgeOpFromBuilder(builder, 3, "edge"); - expect(edgeOp.edgeInput).toStrictEqual({ - id1: "1", - id1Type: "User", - edgeType: "edge", - id2: "2", - id2Type: "User", - }); - }); - - test("no id. creating. no options", async () => { - const builder = getCreateBuilder( - new Map([ - ["FirstName", "Jon"], - ["LastName", "Snow"], - ]), - ); - builder.orchestrator.addOutboundEdge("2", "edge", "User"); - - expect( - builder.orchestrator.getInputEdges("edge", WriteOperation.Insert), - ).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - id: "2", - edgeType: "edge", - nodeType: "User", - direction: edgeDirection.outboundEdge, - }), - ]), - ); - expect( - builder.orchestrator.getInputEdges("edge", WriteOperation.Delete), - ).toEqual([]); - - // 3 ops, create, outbound, inverse - const edgeOp = await getEdgeOpFromBuilder(builder, 3, "edge"); - expect(edgeOp.edgeInput).toStrictEqual({ - id1: builder.placeholderID, - id1Type: "", - id2: "2", - id2Type: "User", - edgeType: "edge", - }); - }); - - test("no options then add options", async () => { - const builder = getLoggedInBuilder(); - builder.orchestrator.addOutboundEdge("2", "edge", "User"); - - expect( - builder.orchestrator.getInputEdges("edge", WriteOperation.Insert), - ).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - id: "2", - edgeType: "edge", - nodeType: "User", - direction: edgeDirection.outboundEdge, - }), - ]), - ); - expect( - builder.orchestrator.getInputEdges("edge", WriteOperation.Delete), - ).toEqual([]); - - builder.orchestrator.addOutboundEdge("2", "edge", "User", { - data: "123456", - }); - expect( - builder.orchestrator.getInputEdges("edge", WriteOperation.Insert), - ).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - id: "2", - edgeType: "edge", - nodeType: "User", - direction: edgeDirection.outboundEdge, - options: { - data: "123456", - }, - }), - ]), - ); - expect( - builder.orchestrator.getInputEdges("edge", WriteOperation.Delete), - ).toEqual([]); - - const edgeOp = await getEdgeOpFromBuilder(builder, 3, "edge"); - expect(edgeOp.edgeInput).toStrictEqual({ - id1: "1", - id1Type: "User", - edgeType: "edge", - id2: "2", - id2Type: "User", - data: "123456", - }); - }); - - test("no id. creating. no options, then add options", async () => { - const builder = getCreateBuilder( - new Map([ - ["FirstName", "Jon"], - ["LastName", "Snow"], - ]), - ); - builder.orchestrator.addOutboundEdge("2", "edge", "User"); - - expect( - builder.orchestrator.getInputEdges("edge", WriteOperation.Insert), - ).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - id: "2", - edgeType: "edge", - nodeType: "User", - direction: edgeDirection.outboundEdge, - }), - ]), - ); - expect( - builder.orchestrator.getInputEdges("edge", WriteOperation.Delete), - ).toEqual([]); - - builder.orchestrator.addOutboundEdge("2", "edge", "User", { - data: "123456", - }); - expect( - builder.orchestrator.getInputEdges("edge", WriteOperation.Insert), - ).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - id: "2", - edgeType: "edge", - nodeType: "User", - direction: edgeDirection.outboundEdge, - options: { - data: "123456", - }, - }), - ]), - ); - expect( - builder.orchestrator.getInputEdges("edge", WriteOperation.Delete), - ).toEqual([]); - - // 3 ops, edit, outbound, inverse - const edgeOp = await getEdgeOpFromBuilder(builder, 3, "edge"); - expect(edgeOp.edgeInput).toStrictEqual({ - id2: "2", - id2Type: "User", - edgeType: "edge", - id1: builder.placeholderID, - id1Type: "", - data: "123456", - }); - }); - - test("options then diff options", async () => { - const builder = getLoggedInBuilder(); - builder.orchestrator.addOutboundEdge("2", "edge", "User", { - data: "123456", - }); - - expect( - builder.orchestrator.getInputEdges("edge", WriteOperation.Insert), - ).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - id: "2", - edgeType: "edge", - nodeType: "User", - direction: edgeDirection.outboundEdge, - options: { - data: "123456", - }, - }), - ]), - ); - expect( - builder.orchestrator.getInputEdges("edge", WriteOperation.Delete), - ).toEqual([]); - - let date = new Date(); - builder.orchestrator.addOutboundEdge("2", "edge", "User", { - data: "123456", - time: date, - }); - expect( - builder.orchestrator.getInputEdges("edge", WriteOperation.Insert), - ).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - id: "2", - edgeType: "edge", - nodeType: "User", - direction: edgeDirection.outboundEdge, - options: { - data: "123456", - time: date, - }, - }), - ]), - ); - expect( - builder.orchestrator.getInputEdges("edge", WriteOperation.Delete), - ).toEqual([]); - - // 3 ops, edit, outbound, inverse - const edgeOp = await getEdgeOpFromBuilder(builder, 3, "edge"); - expect(edgeOp.edgeInput).toStrictEqual({ - id1: "1", - id1Type: "User", - edgeType: "edge", - id2: "2", - id2Type: "User", - data: "123456", - time: date, - }); - }); - - test("no id. creating. options, then diff options", async () => { - const builder = getCreateBuilder( - new Map([ - ["FirstName", "Jon"], - ["LastName", "Snow"], - ]), - ); - builder.orchestrator.addOutboundEdge("2", "edge", "User", { - data: "123456", - }); - - expect( - builder.orchestrator.getInputEdges("edge", WriteOperation.Insert), - ).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - id: "2", - edgeType: "edge", - nodeType: "User", - direction: edgeDirection.outboundEdge, - options: { - data: "123456", - }, - }), - ]), - ); - expect( - builder.orchestrator.getInputEdges("edge", WriteOperation.Delete), - ).toEqual([]); - - // NOTE: data wasn't set in re-adding so it's removed... - let date = new Date(); - builder.orchestrator.addOutboundEdge("2", "edge", "User", { - time: date, - }); - expect( - builder.orchestrator.getInputEdges("edge", WriteOperation.Insert), - ).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - id: "2", - edgeType: "edge", - nodeType: "User", - direction: edgeDirection.outboundEdge, - options: { - time: date, - }, - }), - ]), - ); - expect( - builder.orchestrator.getInputEdges("edge", WriteOperation.Delete), - ).toEqual([]); - - // 3 ops, edit, outbound, inverse - const edgeOp = await getEdgeOpFromBuilder(builder, 3, "edge"); - expect(edgeOp.edgeInput).toStrictEqual({ - id2: "2", - id2Type: "User", - edgeType: "edge", - id1: builder.placeholderID, - id1Type: "", - time: date, - }); - }); - - test("id in data field with placeholder", async () => { - // create user1 - const user = await createUser( - new Map([ - ["FirstName", "Arya"], - ["LastName", "Stark"], - ]), - ); - - const action = getInsertUserAction( - new Map([ - ["FirstName", "Jon"], - ["LastName", "Snow"], - ]), - ); - action.builder.orchestrator.addOutboundEdge(user.id, "edge", "User"); - action.getTriggers = () => [ - { - changeset: (builder: SimpleBuilder) => { - const derivedAction = getInsertUserAction( - new Map([ - ["FirstName", "Sansa"], - ["LastName", "Stark"], - ]), - ); - - // take the edges and write it as 3 edge - const edges = builder.orchestrator.getInputEdges( - "edge", - WriteOperation.Insert, - ); - edges.forEach((edge) => { - builder.orchestrator.addOutboundEdge( - edge.id, - edge.edgeType, - edge.nodeType!, - { - data: derivedAction.builder, - }, - ); - }); - - return derivedAction.changeset(); - }, - }, - ]; - - const newUser = await action.saveX(); - expect(newUser).toBeInstanceOf(User); - if (!newUser) { - throw new Error("impossible"); - } - - const edges = await loadEdges({ - id1: newUser.id, - edgeType: "edge", - }); - expect(edges.length).toBe(1); - const edge = edges[0]; - expect(edge.id1).toBe(newUser.id); - expect(edge.id2).toBe(user.id); - expect(edge.data).toBeDefined(); - - // we were able to resolve the id correctly and then set it as needed - const sansaData = await loadRow({ - tableName: "users", - fields: ["first_name", "last_name"], - clause: clause.Eq("id", edge.data), - }); - expect(sansaData).not.toBeNull(); - expect(sansaData?.first_name).toBe("Sansa"); - expect(sansaData?.last_name).toBe("Stark"); - - // load inverse - const inverseEdges = await loadEdges({ - id1: user.id, - edgeType: "inverseEdge", - }); - expect(inverseEdges.length).toBe(1); - const inverseEdge = inverseEdges[0]; - expect(inverseEdge.data).toBe(edge.data); - }); - }); - - test("id in data field symmetric edge", async () => { - const user = await createUser( - new Map([ - ["FirstName", "Arya"], - ["LastName", "Stark"], - ]), - ); - - const action = getInsertUserAction( - new Map([ - ["FirstName", "Jon"], - ["LastName", "Snow"], - ]), - ); - action.builder.orchestrator.addOutboundEdge( - user.id, - "symmetricEdge", - "User", - ); - action.getTriggers = () => [ - { - changeset: (builder: SimpleBuilder) => { - const derivedAction = getInsertUserAction( - new Map([ - ["FirstName", "Sansa"], - ["LastName", "Stark"], - ]), - ); - - // take the edges and write it as 3 edge - const edges = builder.orchestrator.getInputEdges( - "symmetricEdge", - WriteOperation.Insert, - ); - edges.forEach((edge) => { - builder.orchestrator.addOutboundEdge( - edge.id, - edge.edgeType, - edge.nodeType!, - { - data: derivedAction.builder, - }, - ); - }); - - return derivedAction.changeset(); - }, - }, - ]; - - const newUser = await action.saveX(); - expect(newUser).toBeInstanceOf(User); - if (!newUser) { - throw new Error("impossible"); - } - - const edges = await loadEdges({ - id1: user.id, - edgeType: "symmetricEdge", - }); - expect(edges.length).toBe(1); - const edge = edges[0]; - expect(edge.id1).toBe(user.id); - expect(edge.id2).toBe(newUser.id); - expect(edge.data).not.toBeNull(); - - // we were able to resolve the id correctly and then set it as needed - const sansaData = await loadRow({ - tableName: "users", - fields: ["first_name", "last_name"], - clause: clause.Eq("id", edge.data), - }); - expect(sansaData).toBeDefined(); - expect(sansaData?.first_name).toBe("Sansa"); - expect(sansaData?.last_name).toBe("Stark"); - - const inverseEdges = await loadEdges({ - id1: newUser.id, - edgeType: "symmetricEdge", - }); - expect(inverseEdges.length).toBe(1); - expect(inverseEdges[0].data).toBe(edge.data); - }); - - test("multi-ids then take and add to other edge", async () => { - const builder = getLoggedInBuilder(); - let ids = ["2", "3", "4", "5", "6", "7", "8", "9", "10"]; - let expEdges: any[] = []; - let otherExpEdges: any[] = []; - - ids.forEach((id) => { - builder.orchestrator.addOutboundEdge(id, "edge", "User"); - expEdges.push( - expect.objectContaining({ - id: id, - edgeType: "edge", - nodeType: "User", - direction: edgeDirection.outboundEdge, - }), - ); - - otherExpEdges.push( - expect.objectContaining({ - id: id, - edgeType: "otherEdge", - nodeType: "User", - direction: edgeDirection.outboundEdge, - }), - ); - }); - - let edges = builder.orchestrator.getInputEdges( - "edge", - WriteOperation.Insert, - ); - expect(edges).toEqual(expect.arrayContaining(expEdges)); - - expect( - builder.orchestrator.getInputEdges("otherEdge", WriteOperation.Insert), - ).toEqual([]); - - edges.forEach((edge) => { - builder.orchestrator.addOutboundEdge( - edge.id, - "otherEdge", - edge.nodeType!, - ); - }); - - expect( - builder.orchestrator.getInputEdges("otherEdge", WriteOperation.Insert), - ).toEqual(expect.arrayContaining(otherExpEdges)); - - // clears all the edges - builder.orchestrator.clearInputEdges("edge", WriteOperation.Insert); - expect( - builder.orchestrator.getInputEdges("edge", WriteOperation.Insert), - ).toEqual([]); - - // clear just one id "3" - ids = ids.filter((id) => id != "3"); - builder.orchestrator.clearInputEdges( - "otherEdge", - WriteOperation.Insert, - "3", - ); - otherExpEdges = []; - ids.forEach((id) => { - otherExpEdges.push( - expect.objectContaining({ - id: id, - edgeType: "otherEdge", - nodeType: "User", - direction: edgeDirection.outboundEdge, - }), - ); - }); - expect( - builder.orchestrator.getInputEdges("otherEdge", WriteOperation.Insert), - ).toEqual(otherExpEdges); - }); - - describe("remove inbound edge", () => { - test("existing ent", async () => { - const viewer = new IDViewer("1"); - const user = new User(viewer, { id: "1" }); - const builder = new SimpleBuilder( - viewer, - UserSchema, - new Map(), - WriteOperation.Edit, - user, // TODO enforce existing ent if not create - ); - builder.orchestrator.removeInboundEdge("2", "edge"); - - expect( - builder.orchestrator.getInputEdges("edge", WriteOperation.Delete), - ).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - id: "2", - edgeType: "edge", - direction: edgeDirection.inboundEdge, - }), - ]), - ); - expect( - builder.orchestrator.getInputEdges("edge", WriteOperation.Insert), - ).toEqual([]); - - const edgeOp = await getEdgeOpFromBuilder(builder, 3, "edge"); - expect(edgeOp.edgeInput).toStrictEqual({ - id1: "2", - edgeType: "edge", - id2: "1", - id1Type: "", // not useful so we don't care - id2Type: "", - }); - }); - - test("no ent", async () => { - const builder = new SimpleBuilder( - new LoggedOutViewer(), - UserSchema, - new Map(), - WriteOperation.Edit, - null, - ); - builder.orchestrator.removeInboundEdge("2", "edge"); - - try { - await builder.build(); - - throw new Error("should not get here"); - } catch (e) { - expect(e.message).toBe("existing ent required with operation edit"); - } - }); - }); - - describe("remove outbound edge", () => { - test("existing ent", async () => { - const viewer = new IDViewer("1"); - const user = new User(viewer, { id: "1" }); - const builder = new SimpleBuilder( - viewer, - UserSchema, - new Map(), - WriteOperation.Edit, - user, // TODO enforce existing ent if not create - ); - builder.orchestrator.removeOutboundEdge("2", "edge"); - expect( - builder.orchestrator.getInputEdges("edge", WriteOperation.Insert), - ).toEqual([]); - - expect( - builder.orchestrator.getInputEdges("edge", WriteOperation.Delete), - ).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - id: "2", - edgeType: "edge", - direction: edgeDirection.outboundEdge, - }), - ]), - ); - - const edgeOp = await getEdgeOpFromBuilder(builder, 3, "edge"); - expect(edgeOp.edgeInput).toStrictEqual({ - id1: "1", - edgeType: "edge", - id2: "2", - id1Type: "", // not useful so we don't care - id2Type: "", - }); - }); - - test("no ent", async () => { - const builder = new SimpleBuilder( - new LoggedOutViewer(), - UserSchema, - new Map(), - WriteOperation.Edit, - null, - ); - builder.orchestrator.removeOutboundEdge("2", "edge"); - - try { - await builder.build(); - throw new Error("should not get here"); - } catch (e) { - expect(e.message).toBe("existing ent required with operation edit"); - } - }); - }); - describe("validators", () => { const validators: Validator>[] = [ { @@ -2810,18 +1701,6 @@ function commonTests() { }); } -const getLoggedInBuilder = () => { - const viewer = new IDViewer("1"); - const user = new User(viewer, { id: "1" }); - return new SimpleBuilder( - viewer, - UserSchema, - new Map(), - WriteOperation.Edit, - user, // TODO enforce existing ent if not create - ); -}; - const getCreateBuilder = (map: Map) => { return new SimpleBuilder( new LoggedOutViewer(), @@ -2878,28 +1757,6 @@ async function getFieldsFromBuilder( ); } -async function getEdgeOpFromBuilder( - builder: Builder, - expLength: number, - edgeType: string, -): Promise { - const c = await builder.build(); - const ops = getOperations(c); - expect(ops.length).toBe(expLength); - // console.log(ops); - for (const op of ops) { - if ((op as EdgeOperation).edgeInput !== undefined) { - // console.log(op); - // todo add more things to differentiate this by - const edgeOp = (op as EdgeOperation)!; - if (edgeOp.edgeInput.edgeType === edgeType) { - return edgeOp; - } - } - } - throw new Error(`could not find edge operation with edgeType ${edgeType}`); -} - let sendEmailObserver: Observer> = { observe: (builder): void => { let email = builder.fields.get("EmailAddress"); diff --git a/ts/src/action/orchestrator.ts b/ts/src/action/orchestrator.ts index c4e3c1376..63bd54309 100644 --- a/ts/src/action/orchestrator.ts +++ b/ts/src/action/orchestrator.ts @@ -34,6 +34,7 @@ import { ListBasedExecutor, ComplexExecutor } from "./executor"; import { log } from "../core/logger"; import { Trigger } from "./action"; import memoize from "memoizee"; +import * as clause from "../core/clause"; type MaybeNull = T | null; type TMaybleNullableEnt = T | MaybeNull; @@ -323,6 +324,7 @@ export class Orchestrator< key: this.options.key, loadEntOptions: this.options.loaderOptions, placeholderID: this.options.builder.placeholderID, + whereClause: clause.Eq(this.options.key, this.existingEnt?.id), }; if (this.logValues) { opts.fieldsToLog = this.logValues; diff --git a/ts/src/action/orchestrator_edge.test.ts b/ts/src/action/orchestrator_edge.test.ts new file mode 100644 index 000000000..1c664c6e9 --- /dev/null +++ b/ts/src/action/orchestrator_edge.test.ts @@ -0,0 +1,1292 @@ +import { Builder, WriteOperation } from "../action"; +import { Ent, Viewer } from "../core/base"; +import { DataOperation, EdgeOperation, loadEdges, loadRow } from "../core/ent"; +import { LoggedOutViewer, IDViewer } from "../core/viewer"; +import { Changeset } from "../action"; +import { StringType } from "../schema/field"; +import { + User, + SimpleBuilder, + SimpleAction, + getBuilderSchemaFromFields, +} from "../testutils/builder"; +import { FakeComms } from "../testutils/fake_comms"; +import { Pool } from "pg"; +import { QueryRecorder } from "../testutils/db_mock"; +import { edgeDirection } from "./orchestrator"; +import { createRowForTest } from "../testutils/write"; +import * as clause from "../core/clause"; +import { snakeCase } from "snake-case"; +import { + assoc_edge_config_table, + assoc_edge_table, + getSchemaTable, + setupSqlite, + Table, +} from "../testutils/db/temp_db"; +import { Dialect } from "../core/db"; + +jest.mock("pg"); +QueryRecorder.mockPool(Pool); + +const edges = ["edge", "inverseEdge", "symmetricEdge"]; +beforeEach(async () => { + // does assoc_edge_config loader need to be cleared? + for (const edge of edges) { + await createRowForTest({ + tableName: "assoc_edge_config", + fields: { + edge_table: `${snakeCase(edge)}_table`, + symmetric_edge: edge == "symmetricEdge", + inverse_edge_type: edge === "edge" ? "inverseEdge" : "edge", + edge_type: edge, + edge_name: "name", + created_at: new Date(), + updated_at: new Date(), + }, + }); + } +}); + +afterEach(() => { + QueryRecorder.clear(); + FakeComms.clear(); +}); + +const UserSchema = getBuilderSchemaFromFields( + { + FirstName: StringType(), + LastName: StringType(), + }, + User, +); + +describe("postgres", () => { + commonTests(); +}); + +describe("sqlite", () => { + const getTables = () => { + const tables: Table[] = [assoc_edge_config_table()]; + edges.map((edge) => + tables.push(assoc_edge_table(`${snakeCase(edge)}_table`)), + ); + + [UserSchema].map((s) => tables.push(getSchemaTable(s, Dialect.SQLite))); + + return tables; + }; + + setupSqlite(`sqlite:///orchestrator-edge-test.db`, getTables); + commonTests(); +}); + +const getLoggedInBuilder = () => { + const viewer = new IDViewer("1"); + const user = new User(viewer, { id: "1" }); + return new SimpleBuilder( + viewer, + UserSchema, + new Map(), + WriteOperation.Edit, + user, // TODO enforce existing ent if not create + ); +}; + +function getOperations(c: Changeset): DataOperation[] { + let ops: DataOperation[] = []; + for (let op of c.executor()) { + ops.push(op); + } + return ops; +} + +async function getEdgeOpFromBuilder( + builder: Builder, + expLength: number, + edgeType: string, +): Promise { + const c = await builder.build(); + const ops = getOperations(c); + expect(ops.length).toBe(expLength); + // console.log(ops); + for (const op of ops) { + if ((op as EdgeOperation).edgeInput !== undefined) { + // console.log(op); + // todo add more things to differentiate this by + const edgeOp = (op as EdgeOperation)!; + if (edgeOp.edgeInput.edgeType === edgeType) { + return edgeOp; + } + } + } + throw new Error(`could not find edge operation with edgeType ${edgeType}`); +} + +function getInsertUserAction( + map: Map, + viewer: Viewer = new LoggedOutViewer(), +) { + return new SimpleAction(viewer, UserSchema, map, WriteOperation.Insert, null); +} + +const getCreateBuilder = (map: Map) => { + return new SimpleBuilder( + new LoggedOutViewer(), + UserSchema, + map, + WriteOperation.Insert, + null, + ); +}; + +const createUser = async (map: Map): Promise => { + const builder = getCreateBuilder(map); + + // const + await builder.saveX(); + return builder.editedEntX(); +}; + +function commonTests() { + describe("inbound edge", () => { + test("no options", async () => { + const builder = getLoggedInBuilder(); + builder.orchestrator.addInboundEdge("2", "edge", "User"); + + expect( + builder.orchestrator.getInputEdges("edge", WriteOperation.Insert), + ).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + id: "2", + edgeType: "edge", + nodeType: "User", + direction: edgeDirection.inboundEdge, + }), + ]), + ); + expect( + builder.orchestrator.getInputEdges("edge", WriteOperation.Delete), + ).toEqual([]); + + const edgeOp = await getEdgeOpFromBuilder(builder, 3, "edge"); + expect(edgeOp.edgeInput).toStrictEqual({ + id1: "2", + id1Type: "User", + edgeType: "edge", + id2: "1", + id2Type: "User", + }); + }); + + test("no id. creating. no options", async () => { + const builder = getCreateBuilder( + new Map([ + ["FirstName", "Jon"], + ["LastName", "Snow"], + ]), + ); + builder.orchestrator.addInboundEdge("2", "edge", "User"); + + expect( + builder.orchestrator.getInputEdges("edge", WriteOperation.Insert), + ).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + id: "2", + edgeType: "edge", + nodeType: "User", + direction: edgeDirection.inboundEdge, + }), + ]), + ); + expect( + builder.orchestrator.getInputEdges("edge", WriteOperation.Delete), + ).toEqual([]); + + const edgeOp = await getEdgeOpFromBuilder(builder, 3, "edge"); + expect(edgeOp.edgeInput).toStrictEqual({ + id1: "2", + id1Type: "User", + edgeType: "edge", + id2: builder.placeholderID, + id2Type: "", + }); + }); + + test("no options then add options", async () => { + const builder = getLoggedInBuilder(); + builder.orchestrator.addInboundEdge("2", "edge", "User"); + + expect( + builder.orchestrator.getInputEdges("edge", WriteOperation.Insert), + ).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + id: "2", + edgeType: "edge", + nodeType: "User", + direction: edgeDirection.inboundEdge, + }), + ]), + ); + expect( + builder.orchestrator.getInputEdges("edge", WriteOperation.Delete), + ).toEqual([]); + + builder.orchestrator.addInboundEdge("2", "edge", "User", { + data: "123456", + }); + expect( + builder.orchestrator.getInputEdges("edge", WriteOperation.Insert), + ).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + id: "2", + edgeType: "edge", + nodeType: "User", + direction: edgeDirection.inboundEdge, + options: { + data: "123456", + }, + }), + ]), + ); + expect( + builder.orchestrator.getInputEdges("edge", WriteOperation.Delete), + ).toEqual([]); + + const edgeOp = await getEdgeOpFromBuilder(builder, 3, "edge"); + expect(edgeOp.edgeInput).toStrictEqual({ + id1: "2", + id1Type: "User", + edgeType: "edge", + id2: "1", + id2Type: "User", + data: "123456", + }); + }); + + test("no id. creating. no options, then add options", async () => { + const builder = getCreateBuilder( + new Map([ + ["FirstName", "Jon"], + ["LastName", "Snow"], + ]), + ); + builder.orchestrator.addInboundEdge("2", "edge", "User"); + + expect( + builder.orchestrator.getInputEdges("edge", WriteOperation.Insert), + ).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + id: "2", + edgeType: "edge", + nodeType: "User", + direction: edgeDirection.inboundEdge, + }), + ]), + ); + expect( + builder.orchestrator.getInputEdges("edge", WriteOperation.Delete), + ).toEqual([]); + + builder.orchestrator.addInboundEdge("2", "edge", "User", { + data: "123456", + }); + expect( + builder.orchestrator.getInputEdges("edge", WriteOperation.Insert), + ).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + id: "2", + edgeType: "edge", + nodeType: "User", + direction: edgeDirection.inboundEdge, + options: { + data: "123456", + }, + }), + ]), + ); + expect( + builder.orchestrator.getInputEdges("edge", WriteOperation.Delete), + ).toEqual([]); + + const edgeOp = await getEdgeOpFromBuilder(builder, 3, "edge"); + expect(edgeOp.edgeInput).toStrictEqual({ + id1: "2", + id1Type: "User", + edgeType: "edge", + id2: builder.placeholderID, + id2Type: "", + data: "123456", + }); + }); + + test("options then diff options", async () => { + const builder = getLoggedInBuilder(); + builder.orchestrator.addInboundEdge("2", "edge", "User", { + data: "123456", + }); + + expect( + builder.orchestrator.getInputEdges("edge", WriteOperation.Insert), + ).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + id: "2", + edgeType: "edge", + nodeType: "User", + direction: edgeDirection.inboundEdge, + options: { + data: "123456", + }, + }), + ]), + ); + expect( + builder.orchestrator.getInputEdges("edge", WriteOperation.Delete), + ).toEqual([]); + + let date = new Date(); + builder.orchestrator.addInboundEdge("2", "edge", "User", { + data: "123456", + time: date, + }); + expect( + builder.orchestrator.getInputEdges("edge", WriteOperation.Insert), + ).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + id: "2", + edgeType: "edge", + nodeType: "User", + direction: edgeDirection.inboundEdge, + options: { + data: "123456", + time: date, + }, + }), + ]), + ); + expect( + builder.orchestrator.getInputEdges("edge", WriteOperation.Delete), + ).toEqual([]); + + const edgeOp = await getEdgeOpFromBuilder(builder, 3, "edge"); + expect(edgeOp.edgeInput).toStrictEqual({ + id1: "2", + id1Type: "User", + edgeType: "edge", + id2: "1", + id2Type: "User", + data: "123456", + time: date, + }); + }); + + test("no id. creating. options, then diff options", async () => { + const builder = getCreateBuilder( + new Map([ + ["FirstName", "Jon"], + ["LastName", "Snow"], + ]), + ); + builder.orchestrator.addInboundEdge("2", "edge", "User", { + data: "123456", + }); + + expect( + builder.orchestrator.getInputEdges("edge", WriteOperation.Insert), + ).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + id: "2", + edgeType: "edge", + nodeType: "User", + direction: edgeDirection.inboundEdge, + options: { + data: "123456", + }, + }), + ]), + ); + expect( + builder.orchestrator.getInputEdges("edge", WriteOperation.Delete), + ).toEqual([]); + + // NOTE: data wasn't set in re-adding so it's removed... + let date = new Date(); + builder.orchestrator.addInboundEdge("2", "edge", "User", { + time: date, + }); + expect( + builder.orchestrator.getInputEdges("edge", WriteOperation.Insert), + ).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + id: "2", + edgeType: "edge", + nodeType: "User", + direction: edgeDirection.inboundEdge, + options: { + time: date, + }, + }), + ]), + ); + expect( + builder.orchestrator.getInputEdges("edge", WriteOperation.Delete), + ).toEqual([]); + + const edgeOp = await getEdgeOpFromBuilder(builder, 3, "edge"); + expect(edgeOp.edgeInput).toStrictEqual({ + id1: "2", + id1Type: "User", + edgeType: "edge", + id2: builder.placeholderID, + id2Type: "", + time: date, + }); + }); + + test("id in data field with placeholder", async () => { + // create user1 + const user = await createUser( + new Map([ + ["FirstName", "Arya"], + ["LastName", "Stark"], + ]), + ); + + const action = getInsertUserAction( + new Map([ + ["FirstName", "Jon"], + ["LastName", "Snow"], + ]), + ); + action.builder.orchestrator.addInboundEdge(user.id, "edge", "User"); + action.getTriggers = () => [ + { + changeset: (builder: SimpleBuilder) => { + const derivedAction = getInsertUserAction( + new Map([ + ["FirstName", "Sansa"], + ["LastName", "Stark"], + ]), + ); + + // take the edges and write it as 3 edge + const edges = builder.orchestrator.getInputEdges( + "edge", + WriteOperation.Insert, + ); + edges.forEach((edge) => { + builder.orchestrator.addInboundEdge( + edge.id, + edge.edgeType, + edge.nodeType!, + { + data: derivedAction.builder, + }, + ); + }); + + return derivedAction.changeset(); + }, + }, + ]; + + const newUser = await action.saveX(); + expect(newUser).toBeInstanceOf(User); + if (!newUser) { + throw new Error("impossible"); + } + + const edges = await loadEdges({ + id1: user.id, + edgeType: "edge", + }); + expect(edges.length).toBe(1); + const edge = edges[0]; + expect(edge.id1).toBe(user.id); + expect(edge.id2).toBe(newUser.id); + expect(edge.data).not.toBeNull(); + + // we were able to resolve the id correctly and then set it as needed + const sansaData = await loadRow({ + tableName: "users", + fields: ["first_name", "last_name"], + clause: clause.Eq("id", edge.data), + }); + expect(sansaData).toBeDefined(); + expect(sansaData?.first_name).toBe("Sansa"); + expect(sansaData?.last_name).toBe("Stark"); + + const inverseEdges = await loadEdges({ + id1: newUser.id, + edgeType: "inverseEdge", + }); + expect(inverseEdges.length).toBe(1); + expect(inverseEdges[0].data).toBe(edge.data); + }); + + test("id in data field symmetric edge", async () => { + // create user1 + const user = await createUser( + new Map([ + ["FirstName", "Arya"], + ["LastName", "Stark"], + ]), + ); + + const action = getInsertUserAction( + new Map([ + ["FirstName", "Jon"], + ["LastName", "Snow"], + ]), + ); + action.builder.orchestrator.addInboundEdge( + user.id, + "symmetricEdge", + "User", + ); + action.getTriggers = () => [ + { + changeset: (builder: SimpleBuilder) => { + const derivedAction = getInsertUserAction( + new Map([ + ["FirstName", "Sansa"], + ["LastName", "Stark"], + ]), + ); + + // take the edges and write it as 3 edge + const edges = builder.orchestrator.getInputEdges( + "symmetricEdge", + WriteOperation.Insert, + ); + edges.forEach((edge) => { + builder.orchestrator.addInboundEdge( + edge.id, + edge.edgeType, + edge.nodeType!, + { + data: derivedAction.builder, + }, + ); + }); + + return derivedAction.changeset(); + }, + }, + ]; + + const newUser = await action.saveX(); + expect(newUser).toBeInstanceOf(User); + if (!newUser) { + throw new Error("impossible"); + } + + const edges = await loadEdges({ + id1: user.id, + edgeType: "symmetricEdge", + }); + expect(edges.length).toBe(1); + const edge = edges[0]; + expect(edge.id1).toBe(user.id); + expect(edge.id2).toBe(newUser.id); + expect(edge.data).not.toBeNull(); + + // we were able to resolve the id correctly and then set it as needed + const sansaData = await loadRow({ + tableName: "users", + fields: ["first_name", "last_name"], + clause: clause.Eq("id", edge.data), + }); + expect(sansaData).toBeDefined(); + expect(sansaData?.first_name).toBe("Sansa"); + expect(sansaData?.last_name).toBe("Stark"); + + const inverseEdges = await loadEdges({ + id1: newUser.id, + edgeType: "symmetricEdge", + }); + expect(inverseEdges.length).toBe(1); + expect(inverseEdges[0].data).toBe(edge.data); + }); + }); + + describe("outbound edge", () => { + test("no options", async () => { + const builder = getLoggedInBuilder(); + builder.orchestrator.addOutboundEdge("2", "edge", "User"); + + expect( + builder.orchestrator.getInputEdges("edge", WriteOperation.Insert), + ).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + id: "2", + edgeType: "edge", + nodeType: "User", + direction: edgeDirection.outboundEdge, + }), + ]), + ); + expect( + builder.orchestrator.getInputEdges("edge", WriteOperation.Delete), + ).toEqual([]); + + // 3 ops, edit, outbound, inverse + const edgeOp = await getEdgeOpFromBuilder(builder, 3, "edge"); + expect(edgeOp.edgeInput).toStrictEqual({ + id1: "1", + id1Type: "User", + edgeType: "edge", + id2: "2", + id2Type: "User", + }); + }); + + test("no id. creating. no options", async () => { + const builder = getCreateBuilder( + new Map([ + ["FirstName", "Jon"], + ["LastName", "Snow"], + ]), + ); + builder.orchestrator.addOutboundEdge("2", "edge", "User"); + + expect( + builder.orchestrator.getInputEdges("edge", WriteOperation.Insert), + ).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + id: "2", + edgeType: "edge", + nodeType: "User", + direction: edgeDirection.outboundEdge, + }), + ]), + ); + expect( + builder.orchestrator.getInputEdges("edge", WriteOperation.Delete), + ).toEqual([]); + + // 3 ops, create, outbound, inverse + const edgeOp = await getEdgeOpFromBuilder(builder, 3, "edge"); + expect(edgeOp.edgeInput).toStrictEqual({ + id1: builder.placeholderID, + id1Type: "", + id2: "2", + id2Type: "User", + edgeType: "edge", + }); + }); + + test("no options then add options", async () => { + const builder = getLoggedInBuilder(); + builder.orchestrator.addOutboundEdge("2", "edge", "User"); + + expect( + builder.orchestrator.getInputEdges("edge", WriteOperation.Insert), + ).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + id: "2", + edgeType: "edge", + nodeType: "User", + direction: edgeDirection.outboundEdge, + }), + ]), + ); + expect( + builder.orchestrator.getInputEdges("edge", WriteOperation.Delete), + ).toEqual([]); + + builder.orchestrator.addOutboundEdge("2", "edge", "User", { + data: "123456", + }); + expect( + builder.orchestrator.getInputEdges("edge", WriteOperation.Insert), + ).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + id: "2", + edgeType: "edge", + nodeType: "User", + direction: edgeDirection.outboundEdge, + options: { + data: "123456", + }, + }), + ]), + ); + expect( + builder.orchestrator.getInputEdges("edge", WriteOperation.Delete), + ).toEqual([]); + + const edgeOp = await getEdgeOpFromBuilder(builder, 3, "edge"); + expect(edgeOp.edgeInput).toStrictEqual({ + id1: "1", + id1Type: "User", + edgeType: "edge", + id2: "2", + id2Type: "User", + data: "123456", + }); + }); + + test("no id. creating. no options, then add options", async () => { + const builder = getCreateBuilder( + new Map([ + ["FirstName", "Jon"], + ["LastName", "Snow"], + ]), + ); + builder.orchestrator.addOutboundEdge("2", "edge", "User"); + + expect( + builder.orchestrator.getInputEdges("edge", WriteOperation.Insert), + ).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + id: "2", + edgeType: "edge", + nodeType: "User", + direction: edgeDirection.outboundEdge, + }), + ]), + ); + expect( + builder.orchestrator.getInputEdges("edge", WriteOperation.Delete), + ).toEqual([]); + + builder.orchestrator.addOutboundEdge("2", "edge", "User", { + data: "123456", + }); + expect( + builder.orchestrator.getInputEdges("edge", WriteOperation.Insert), + ).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + id: "2", + edgeType: "edge", + nodeType: "User", + direction: edgeDirection.outboundEdge, + options: { + data: "123456", + }, + }), + ]), + ); + expect( + builder.orchestrator.getInputEdges("edge", WriteOperation.Delete), + ).toEqual([]); + + // 3 ops, edit, outbound, inverse + const edgeOp = await getEdgeOpFromBuilder(builder, 3, "edge"); + expect(edgeOp.edgeInput).toStrictEqual({ + id2: "2", + id2Type: "User", + edgeType: "edge", + id1: builder.placeholderID, + id1Type: "", + data: "123456", + }); + }); + + test("options then diff options", async () => { + const builder = getLoggedInBuilder(); + builder.orchestrator.addOutboundEdge("2", "edge", "User", { + data: "123456", + }); + + expect( + builder.orchestrator.getInputEdges("edge", WriteOperation.Insert), + ).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + id: "2", + edgeType: "edge", + nodeType: "User", + direction: edgeDirection.outboundEdge, + options: { + data: "123456", + }, + }), + ]), + ); + expect( + builder.orchestrator.getInputEdges("edge", WriteOperation.Delete), + ).toEqual([]); + + let date = new Date(); + builder.orchestrator.addOutboundEdge("2", "edge", "User", { + data: "123456", + time: date, + }); + expect( + builder.orchestrator.getInputEdges("edge", WriteOperation.Insert), + ).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + id: "2", + edgeType: "edge", + nodeType: "User", + direction: edgeDirection.outboundEdge, + options: { + data: "123456", + time: date, + }, + }), + ]), + ); + expect( + builder.orchestrator.getInputEdges("edge", WriteOperation.Delete), + ).toEqual([]); + + // 3 ops, edit, outbound, inverse + const edgeOp = await getEdgeOpFromBuilder(builder, 3, "edge"); + expect(edgeOp.edgeInput).toStrictEqual({ + id1: "1", + id1Type: "User", + edgeType: "edge", + id2: "2", + id2Type: "User", + data: "123456", + time: date, + }); + }); + + test("no id. creating. options, then diff options", async () => { + const builder = getCreateBuilder( + new Map([ + ["FirstName", "Jon"], + ["LastName", "Snow"], + ]), + ); + builder.orchestrator.addOutboundEdge("2", "edge", "User", { + data: "123456", + }); + + expect( + builder.orchestrator.getInputEdges("edge", WriteOperation.Insert), + ).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + id: "2", + edgeType: "edge", + nodeType: "User", + direction: edgeDirection.outboundEdge, + options: { + data: "123456", + }, + }), + ]), + ); + expect( + builder.orchestrator.getInputEdges("edge", WriteOperation.Delete), + ).toEqual([]); + + // NOTE: data wasn't set in re-adding so it's removed... + let date = new Date(); + builder.orchestrator.addOutboundEdge("2", "edge", "User", { + time: date, + }); + expect( + builder.orchestrator.getInputEdges("edge", WriteOperation.Insert), + ).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + id: "2", + edgeType: "edge", + nodeType: "User", + direction: edgeDirection.outboundEdge, + options: { + time: date, + }, + }), + ]), + ); + expect( + builder.orchestrator.getInputEdges("edge", WriteOperation.Delete), + ).toEqual([]); + + // 3 ops, edit, outbound, inverse + const edgeOp = await getEdgeOpFromBuilder(builder, 3, "edge"); + expect(edgeOp.edgeInput).toStrictEqual({ + id2: "2", + id2Type: "User", + edgeType: "edge", + id1: builder.placeholderID, + id1Type: "", + time: date, + }); + }); + + test("id in data field with placeholder", async () => { + // create user1 + const user = await createUser( + new Map([ + ["FirstName", "Arya"], + ["LastName", "Stark"], + ]), + ); + + const action = getInsertUserAction( + new Map([ + ["FirstName", "Jon"], + ["LastName", "Snow"], + ]), + ); + action.builder.orchestrator.addOutboundEdge(user.id, "edge", "User"); + action.getTriggers = () => [ + { + changeset: (builder: SimpleBuilder) => { + const derivedAction = getInsertUserAction( + new Map([ + ["FirstName", "Sansa"], + ["LastName", "Stark"], + ]), + ); + + // take the edges and write it as 3 edge + const edges = builder.orchestrator.getInputEdges( + "edge", + WriteOperation.Insert, + ); + edges.forEach((edge) => { + builder.orchestrator.addOutboundEdge( + edge.id, + edge.edgeType, + edge.nodeType!, + { + data: derivedAction.builder, + }, + ); + }); + + return derivedAction.changeset(); + }, + }, + ]; + + const newUser = await action.saveX(); + expect(newUser).toBeInstanceOf(User); + if (!newUser) { + throw new Error("impossible"); + } + + const edges = await loadEdges({ + id1: newUser.id, + edgeType: "edge", + }); + expect(edges.length).toBe(1); + const edge = edges[0]; + expect(edge.id1).toBe(newUser.id); + expect(edge.id2).toBe(user.id); + expect(edge.data).toBeDefined(); + + // we were able to resolve the id correctly and then set it as needed + const sansaData = await loadRow({ + tableName: "users", + fields: ["first_name", "last_name"], + clause: clause.Eq("id", edge.data), + }); + expect(sansaData).not.toBeNull(); + expect(sansaData?.first_name).toBe("Sansa"); + expect(sansaData?.last_name).toBe("Stark"); + + // load inverse + const inverseEdges = await loadEdges({ + id1: user.id, + edgeType: "inverseEdge", + }); + expect(inverseEdges.length).toBe(1); + const inverseEdge = inverseEdges[0]; + expect(inverseEdge.data).toBe(edge.data); + }); + }); + + test("id in data field symmetric edge", async () => { + const user = await createUser( + new Map([ + ["FirstName", "Arya"], + ["LastName", "Stark"], + ]), + ); + + const action = getInsertUserAction( + new Map([ + ["FirstName", "Jon"], + ["LastName", "Snow"], + ]), + ); + action.builder.orchestrator.addOutboundEdge( + user.id, + "symmetricEdge", + "User", + ); + action.getTriggers = () => [ + { + changeset: (builder: SimpleBuilder) => { + const derivedAction = getInsertUserAction( + new Map([ + ["FirstName", "Sansa"], + ["LastName", "Stark"], + ]), + ); + + // take the edges and write it as 3 edge + const edges = builder.orchestrator.getInputEdges( + "symmetricEdge", + WriteOperation.Insert, + ); + edges.forEach((edge) => { + builder.orchestrator.addOutboundEdge( + edge.id, + edge.edgeType, + edge.nodeType!, + { + data: derivedAction.builder, + }, + ); + }); + + return derivedAction.changeset(); + }, + }, + ]; + + const newUser = await action.saveX(); + expect(newUser).toBeInstanceOf(User); + if (!newUser) { + throw new Error("impossible"); + } + + const edges = await loadEdges({ + id1: user.id, + edgeType: "symmetricEdge", + }); + expect(edges.length).toBe(1); + const edge = edges[0]; + expect(edge.id1).toBe(user.id); + expect(edge.id2).toBe(newUser.id); + expect(edge.data).not.toBeNull(); + + // we were able to resolve the id correctly and then set it as needed + const sansaData = await loadRow({ + tableName: "users", + fields: ["first_name", "last_name"], + clause: clause.Eq("id", edge.data), + }); + expect(sansaData).toBeDefined(); + expect(sansaData?.first_name).toBe("Sansa"); + expect(sansaData?.last_name).toBe("Stark"); + + const inverseEdges = await loadEdges({ + id1: newUser.id, + edgeType: "symmetricEdge", + }); + expect(inverseEdges.length).toBe(1); + expect(inverseEdges[0].data).toBe(edge.data); + }); + + test("multi-ids then take and add to other edge", async () => { + const builder = getLoggedInBuilder(); + let ids = ["2", "3", "4", "5", "6", "7", "8", "9", "10"]; + let expEdges: any[] = []; + let otherExpEdges: any[] = []; + + ids.forEach((id) => { + builder.orchestrator.addOutboundEdge(id, "edge", "User"); + expEdges.push( + expect.objectContaining({ + id: id, + edgeType: "edge", + nodeType: "User", + direction: edgeDirection.outboundEdge, + }), + ); + + otherExpEdges.push( + expect.objectContaining({ + id: id, + edgeType: "otherEdge", + nodeType: "User", + direction: edgeDirection.outboundEdge, + }), + ); + }); + + let edges = builder.orchestrator.getInputEdges( + "edge", + WriteOperation.Insert, + ); + expect(edges).toEqual(expect.arrayContaining(expEdges)); + + expect( + builder.orchestrator.getInputEdges("otherEdge", WriteOperation.Insert), + ).toEqual([]); + + edges.forEach((edge) => { + builder.orchestrator.addOutboundEdge( + edge.id, + "otherEdge", + edge.nodeType!, + ); + }); + + expect( + builder.orchestrator.getInputEdges("otherEdge", WriteOperation.Insert), + ).toEqual(expect.arrayContaining(otherExpEdges)); + + // clears all the edges + builder.orchestrator.clearInputEdges("edge", WriteOperation.Insert); + expect( + builder.orchestrator.getInputEdges("edge", WriteOperation.Insert), + ).toEqual([]); + + // clear just one id "3" + ids = ids.filter((id) => id != "3"); + builder.orchestrator.clearInputEdges( + "otherEdge", + WriteOperation.Insert, + "3", + ); + otherExpEdges = []; + ids.forEach((id) => { + otherExpEdges.push( + expect.objectContaining({ + id: id, + edgeType: "otherEdge", + nodeType: "User", + direction: edgeDirection.outboundEdge, + }), + ); + }); + expect( + builder.orchestrator.getInputEdges("otherEdge", WriteOperation.Insert), + ).toEqual(otherExpEdges); + }); + + describe("remove inbound edge", () => { + test("existing ent", async () => { + const viewer = new IDViewer("1"); + const user = new User(viewer, { id: "1" }); + const builder = new SimpleBuilder( + viewer, + UserSchema, + new Map(), + WriteOperation.Edit, + user, // TODO enforce existing ent if not create + ); + builder.orchestrator.removeInboundEdge("2", "edge"); + + expect( + builder.orchestrator.getInputEdges("edge", WriteOperation.Delete), + ).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + id: "2", + edgeType: "edge", + direction: edgeDirection.inboundEdge, + }), + ]), + ); + expect( + builder.orchestrator.getInputEdges("edge", WriteOperation.Insert), + ).toEqual([]); + + const edgeOp = await getEdgeOpFromBuilder(builder, 3, "edge"); + expect(edgeOp.edgeInput).toStrictEqual({ + id1: "2", + edgeType: "edge", + id2: "1", + id1Type: "", // not useful so we don't care + id2Type: "", + }); + }); + + test("no ent", async () => { + const builder = new SimpleBuilder( + new LoggedOutViewer(), + UserSchema, + new Map(), + WriteOperation.Edit, + null, + ); + builder.orchestrator.removeInboundEdge("2", "edge"); + + try { + await builder.build(); + + throw new Error("should not get here"); + } catch (e) { + expect(e.message).toBe("existing ent required with operation edit"); + } + }); + }); + + describe("remove outbound edge", () => { + test("existing ent", async () => { + const viewer = new IDViewer("1"); + const user = new User(viewer, { id: "1" }); + const builder = new SimpleBuilder( + viewer, + UserSchema, + new Map(), + WriteOperation.Edit, + user, // TODO enforce existing ent if not create + ); + builder.orchestrator.removeOutboundEdge("2", "edge"); + expect( + builder.orchestrator.getInputEdges("edge", WriteOperation.Insert), + ).toEqual([]); + + expect( + builder.orchestrator.getInputEdges("edge", WriteOperation.Delete), + ).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + id: "2", + edgeType: "edge", + direction: edgeDirection.outboundEdge, + }), + ]), + ); + + const edgeOp = await getEdgeOpFromBuilder(builder, 3, "edge"); + expect(edgeOp.edgeInput).toStrictEqual({ + id1: "1", + edgeType: "edge", + id2: "2", + id1Type: "", // not useful so we don't care + id2Type: "", + }); + }); + + test("no ent", async () => { + const builder = new SimpleBuilder( + new LoggedOutViewer(), + UserSchema, + new Map(), + WriteOperation.Edit, + null, + ); + builder.orchestrator.removeOutboundEdge("2", "edge"); + + try { + await builder.build(); + throw new Error("should not get here"); + } catch (e) { + expect(e.message).toBe("existing ent required with operation edit"); + } + }); + }); +} diff --git a/ts/src/action/orchestrator_edge_data.test.ts b/ts/src/action/orchestrator_edge_data.test.ts new file mode 100644 index 000000000..c049b8eb3 --- /dev/null +++ b/ts/src/action/orchestrator_edge_data.test.ts @@ -0,0 +1,463 @@ +import { WriteOperation } from "../action"; +import { snakeCase } from "snake-case"; +import DB, { Dialect } from "../core/db"; +import { + assoc_edge_config_table, + assoc_edge_table, + getSchemaTable, + setupSqlite, + Table, + TempDB, +} from "../testutils/db/temp_db"; +import { Viewer } from "../core/base"; +import { LoggedOutViewer } from "../core/viewer"; +import { StringType } from "../schema"; +import { + User, + SimpleAction, + getBuilderSchemaFromFields, +} from "../testutils/builder"; +import { createRowForTest } from "../testutils/write"; +import { + AssocEdge, + AssocEdgeConstructor, + clearGlobalSchema, + loadCustomEdges, + loadEdges, + loadRawEdgeCountX, + setGlobalSchema, +} from "../core/ent"; +import { + EdgeWithDeletedAt, + testEdgeGlobalSchema, +} from "../testutils/test_edge_global_schema"; + +const UserSchema = getBuilderSchemaFromFields( + { + FirstName: StringType(), + LastName: StringType(), + }, + User, +); + +function getInsertUserAction( + map: Map, + viewer: Viewer = new LoggedOutViewer(), +) { + return new SimpleAction(viewer, UserSchema, map, WriteOperation.Insert, null); +} + +const edges = ["edge", "inverseEdge", "symmetricEdge"]; + +const getInitialTables = (dialect: Dialect) => { + const tables: Table[] = [assoc_edge_config_table()]; + + [UserSchema].map((s) => tables.push(getSchemaTable(s, dialect))); + + return tables; +}; + +function setupEdgeTables(tdb: TempDB, global = false) { + if (global) { + beforeAll(() => { + setGlobalSchema(testEdgeGlobalSchema); + }); + afterAll(() => { + clearGlobalSchema(); + }); + } + beforeAll(async () => { + await createEdgeRows(); + }); + + afterAll(async () => { + await DB.getInstance().getPool().query("DELETE from assoc_edge_config"); + }); + + beforeEach(async () => { + const tables: Table[] = []; + edges.map((edge) => { + const t = assoc_edge_table(`${snakeCase(edge)}_table`, global); + tables.push(t); + }); + await tdb.create(...tables); + }); + + afterEach(async () => { + await tdb.drop(...edges.map((edge) => `${snakeCase(edge)}_table`)); + }); +} + +async function createEdgeRows() { + for (const edge of edges) { + await createRowForTest({ + tableName: "assoc_edge_config", + fields: { + edge_table: `${snakeCase(edge)}_table`, + symmetric_edge: edge == "symmetricEdge", + inverse_edge_type: edge === "edge" ? "inverseEdge" : "edge", + edge_type: edge, + edge_name: "name", + created_at: new Date(), + updated_at: new Date(), + }, + }); + } +} + +function setupPostgres() { + const tdb = new TempDB(Dialect.Postgres, getInitialTables(Dialect.Postgres)); + + beforeAll(async () => { + await tdb.beforeAll(); + }); + + afterAll(async () => { + await tdb.afterAll(); + }); + return tdb; +} + +describe("postgres", () => { + const tdb = setupPostgres(); + + describe("postgres no global schema", () => { + setupEdgeTables(tdb, false); + commonTestsNoGlobalSchema(); + }); + + describe("postgres global schema", () => { + setupEdgeTables(tdb, true); + commonTestsGlobalSchema(); + }); +}); + +describe("sqlite", () => { + const tdb = setupSqlite(`sqlite:///orchestrator-edge-data-test.db`, () => + getInitialTables(Dialect.SQLite), + ); + + describe("sqlite no global schema", () => { + setupEdgeTables(tdb, false); + commonTestsNoGlobalSchema(); + }); + + describe("sqlite global schema", () => { + setupEdgeTables(tdb, true); + commonTestsGlobalSchema(); + }); +}); + +interface VerifyOptions { + symmetric: User; + inverse: User; + verifyEdge?: (edge: T) => void; +} + +async function doVerifyAddedEdges( + user: User, + ctr: AssocEdgeConstructor, + opts: VerifyOptions, +) { + const verifyEdges = (edges: T[]) => { + if (!opts.verifyEdge) { + return; + } + edges.map((edge) => opts.verifyEdge!(edge)); + }; + const edges = await loadCustomEdges({ + id1: user.id, + edgeType: "edge", + ctr, + }); + const edgesCount = await loadRawEdgeCountX({ + id1: user.id, + edgeType: "edge", + }); + verifyEdges(edges); + expect(edges.length).toBe(2); + expect(edgesCount).toBe(2); + expect( + edges + .map((edge) => edge.id2) + .every((id) => [opts.symmetric.id, opts.inverse.id].includes(id)), + ).toBe(true); + + const symmetricEdges = await loadCustomEdges({ + id1: user.id, + edgeType: "symmetricEdge", + ctr, + }); + verifyEdges(symmetricEdges); + + expect(symmetricEdges.length).toBe(1); + expect(symmetricEdges[0].id2).toBe(opts.symmetric.id); + const symmetricEdgesCount = await loadRawEdgeCountX({ + id1: user.id, + edgeType: "symmetricEdge", + }); + expect(symmetricEdgesCount).toBe(1); + + for (const id of [opts.symmetric.id, opts.inverse.id]) { + const inverseEdges = await loadCustomEdges({ + id1: id, + edgeType: "inverseEdge", + ctr, + }); + expect(inverseEdges.length).toBe(1); + expect(inverseEdges[0].id2).toBe(user.id); + verifyEdges(inverseEdges); + + const inverseEdgesCount = await loadRawEdgeCountX({ + id1: id, + edgeType: "inverseEdge", + }); + expect(inverseEdgesCount).toBe(1); + + if (id === opts.symmetric.id) { + const symmetricEdges = await loadCustomEdges({ + id1: id, + edgeType: "symmetricEdge", + ctr, + }); + expect(symmetricEdges.length).toBe(1); + expect(symmetricEdges[0].id2).toBe(user.id); + verifyEdges(symmetricEdges); + + const symmetricEdgesCount = await loadRawEdgeCountX({ + id1: id, + edgeType: "symmetricEdge", + }); + expect(symmetricEdgesCount).toBe(1); + } + } + + return { edges, symmetricEdges }; +} + +async function doTestAddEdge( + ctr: AssocEdgeConstructor, + verifyEdge?: (edge: T) => void, +) { + const user1 = await getInsertUserAction( + new Map([ + ["FirstName", "Jon"], + ["LastName", "Snow"], + ]), + ).saveX(); + const user2 = await getInsertUserAction( + new Map([ + ["FirstName", "Arya"], + ["LastName", "Stark"], + ]), + ).saveX(); + const action = getInsertUserAction( + new Map([ + ["FirstName", "Sansa"], + ["LastName", "Stark"], + ]), + ); + action.builder.orchestrator.addOutboundEdge(user1.id, "edge", user1.nodeType); + action.builder.orchestrator.addOutboundEdge(user2.id, "edge", user2.nodeType); + + action.builder.orchestrator.addOutboundEdge( + user1.id, + "symmetricEdge", + user1.nodeType, + ); + const user3 = await action.saveX(); + + const { edges, symmetricEdges } = await doVerifyAddedEdges(user3, ctr, { + symmetric: user1, + inverse: user2, + verifyEdge, + }); + + return { + user: user3, + edges, + symmetric: user1, + inverse: user2, + symmetricEdges, + }; +} + +async function doTestRemoveEdge( + ctr: AssocEdgeConstructor, + verifyEdge?: (edge: T) => void, +) { + const { user, symmetric, inverse, edges, symmetricEdges } = + await doTestAddEdge(ctr, verifyEdge); + + const action = new SimpleAction( + user.viewer, + UserSchema, + new Map(), + WriteOperation.Edit, + user, + ); + for (const edge of edges) { + action.builder.orchestrator.removeOutboundEdge(edge.id2, edge.edgeType); + } + for (const edge of symmetricEdges) { + action.builder.orchestrator.removeOutboundEdge(edge.id2, edge.edgeType); + } + await action.saveX(); + + return { user, edges, symmetricEdges, symmetric, inverse }; +} + +async function doTestAddAndRemoveEdge( + ctr: AssocEdgeConstructor, + verifyEdge?: (edge: T) => void, +) { + const { user, edges, symmetricEdges, symmetric, inverse } = + await doTestRemoveEdge(ctr, verifyEdge); + + const action = new SimpleAction( + user.viewer, + UserSchema, + new Map(), + WriteOperation.Edit, + user, + ); + + for (const edge of edges) { + action.builder.orchestrator.addOutboundEdge( + edge.id2, + edge.edgeType, + "user", + ); + } + for (const edge of symmetricEdges) { + action.builder.orchestrator.addOutboundEdge( + edge.id2, + edge.edgeType, + "symmetricEdge", + ); + } + await action.saveX(); + + await doVerifyAddedEdges(user, ctr, { + symmetric, + inverse, + verifyEdge, + }); +} + +function commonTestsNoGlobalSchema() { + test("add edge", async () => { + await doTestAddEdge(AssocEdge); + }); + + test("remove edge", async () => { + const { user } = await doTestRemoveEdge(AssocEdge); + + const reloadEdges = await loadEdges({ + id1: user.id, + edgeType: "edge", + // shouldn't do anything + disableTransformations: true, + }); + const reloadEdgesCount = await loadRawEdgeCountX({ + id1: user.id, + edgeType: "edge", + // shouldn't do anything + disableTransformations: true, + }); + const reloadSymmetricEdges = await loadEdges({ + id1: user.id, + edgeType: "symmetricEdge", + // shouldn't do anything + disableTransformations: true, + }); + const reloadSymmetricEdgesCount = await loadRawEdgeCountX({ + id1: user.id, + edgeType: "symmetricEdge", + // shouldn't do anything + disableTransformations: true, + }); + expect(reloadEdges.length).toBe(0); + expect(reloadSymmetricEdges.length).toBe(0); + + expect(reloadEdgesCount).toBe(0); + expect(reloadSymmetricEdgesCount).toBe(0); + }); + + test("add and remove edge", async () => { + await doTestAddAndRemoveEdge(AssocEdge); + }); +} + +function commonTestsGlobalSchema() { + async function verifyEdge(edge: EdgeWithDeletedAt) { + expect(edge.deletedAt).toBe(null); + } + + test("add edge", async () => { + await doTestAddEdge(EdgeWithDeletedAt, verifyEdge); + }); + + test("remove edge", async () => { + const { user } = await doTestRemoveEdge(EdgeWithDeletedAt, verifyEdge); + + // by default nothing is returned... + const reloadEdges = await loadCustomEdges({ + id1: user.id, + edgeType: "edge", + ctr: EdgeWithDeletedAt, + }); + const reloadEdgesCount = await loadRawEdgeCountX({ + id1: user.id, + edgeType: "edge", + }); + const reloadSymmetricEdges = await loadCustomEdges({ + id1: user.id, + edgeType: "symmetricEdge", + ctr: EdgeWithDeletedAt, + }); + const reloadSymmetricEdgesCount = await loadRawEdgeCountX({ + id1: user.id, + edgeType: "symmetricEdge", + }); + expect(reloadEdges.length).toBe(0); + expect(reloadSymmetricEdges.length).toBe(0); + expect(reloadEdgesCount).toBe(0); + expect(reloadSymmetricEdgesCount).toBe(0); + + // reload with no transformations and we can get the raw data out of it and see the deleted_at flag set to a given time + const reloadEdges2 = await loadCustomEdges({ + id1: user.id, + edgeType: "edge", + disableTransformations: true, + ctr: EdgeWithDeletedAt, + }); + const reloadEdges2Count = await loadRawEdgeCountX({ + id1: user.id, + edgeType: "edge", + disableTransformations: true, + }); + const reloadSymmetricEdges2 = await loadCustomEdges({ + id1: user.id, + edgeType: "symmetricEdge", + disableTransformations: true, + ctr: EdgeWithDeletedAt, + }); + const reloadSymmetricEdges2Count = await loadRawEdgeCountX({ + id1: user.id, + edgeType: "symmetricEdge", + disableTransformations: true, + }); + expect(reloadEdges2.length).toBe(2); + expect(reloadEdges2Count).toBe(2); + reloadEdges2.map((edge) => expect(edge.deletedAt).not.toBeNull()); + + expect(reloadSymmetricEdges2.length).toBe(1); + expect(reloadSymmetricEdges2Count).toBe(1); + reloadSymmetricEdges2.map((edge) => expect(edge.deletedAt).not.toBeNull()); + }); + + test("add and remove edge", async () => { + await doTestAddAndRemoveEdge(EdgeWithDeletedAt, verifyEdge); + }); +} diff --git a/ts/src/action/transformed_orchestrator.test.ts b/ts/src/action/transformed_orchestrator.test.ts index 448b2e490..a6fb72027 100644 --- a/ts/src/action/transformed_orchestrator.test.ts +++ b/ts/src/action/transformed_orchestrator.test.ts @@ -26,7 +26,7 @@ import { getSchemaTable, setupSqlite, Table, -} from "../testutils/db/test_db"; +} from "../testutils/db/temp_db"; import { convertDate } from "../core/convert"; import { loadConfig } from "../core/config"; import { FieldMap } from "../schema"; @@ -61,27 +61,6 @@ afterEach(() => { FakeComms.clear(); }); -describe("postgres", () => { - commonTests(); -}); - -describe("sqlite", () => { - const getTables = () => { - const tables: Table[] = [assoc_edge_config_table()]; - edges.map((edge) => - tables.push(assoc_edge_table(`${snakeCase(edge)}_table`)), - ); - - [new UserSchema(), new ContactSchema()].map((s) => - tables.push(getSchemaTable(s, Dialect.SQLite)), - ); - return tables; - }; - - setupSqlite(`sqlite:///transformed-orchestrator-test.db`, getTables); - commonTests(); -}); - class DeletedAtPattern implements Pattern { name = "deleted_at"; fields: FieldMap = { @@ -172,6 +151,27 @@ class ContactSchema extends BaseEntSchema { ent = Contact; } +describe("postgres", () => { + commonTests(); +}); + +describe("sqlite", () => { + const getTables = () => { + const tables: Table[] = [assoc_edge_config_table()]; + edges.map((edge) => + tables.push(assoc_edge_table(`${snakeCase(edge)}_table`)), + ); + + [new UserSchema(), new ContactSchema()].map((s) => + tables.push(getSchemaTable(s, Dialect.SQLite)), + ); + return tables; + }; + + setupSqlite(`sqlite:///transformed-orchestrator-test.db`, getTables); + commonTests(); +}); + const getNewLoader = (context: boolean = true) => { return new ObjectLoader( { diff --git a/ts/src/action/trigger_priority.test.ts b/ts/src/action/trigger_priority.test.ts index 2fa0f9745..f64c6ff8c 100644 --- a/ts/src/action/trigger_priority.test.ts +++ b/ts/src/action/trigger_priority.test.ts @@ -7,9 +7,8 @@ import { User, SimpleAction, SimpleBuilder } from "../testutils/builder"; import { Pool } from "pg"; import { QueryRecorder } from "../testutils/db_mock"; import { Dialect } from "../core/db"; -import { getSchemaTable, setupSqlite, Table } from "../testutils/db/test_db"; +import { getSchemaTable, setupSqlite, Table } from "../testutils/db/temp_db"; import { FieldMap } from "../schema"; -import exp from "constants"; jest.mock("pg"); QueryRecorder.mockPool(Pool); @@ -22,6 +21,14 @@ describe("postgres", () => { commonTests(); }); +class UserSchema extends BaseEntSchema { + fields: FieldMap = { + FirstName: StringType(), + LastName: StringType(), + }; + ent = User; +} + describe("sqlite", () => { const getTables = () => { const tables: Table[] = []; @@ -35,14 +42,6 @@ describe("sqlite", () => { commonTests(); }); -class UserSchema extends BaseEntSchema { - fields: FieldMap = { - FirstName: StringType(), - LastName: StringType(), - }; - ent = User; -} - function getInsertUserAction( map: Map, viewer: Viewer = new LoggedOutViewer(), diff --git a/ts/src/core/base.ts b/ts/src/core/base.ts index 1b1cd0256..254e4f74c 100644 --- a/ts/src/core/base.ts +++ b/ts/src/core/base.ts @@ -158,7 +158,7 @@ export interface CreateRowOptions extends DataOptions { } export interface EditRowOptions extends CreateRowOptions { - key: string; // what key are we loading from. if not provided we're loading from column "id" + whereClause: clause.Clause; } interface LoadableEntOptions< diff --git a/ts/src/core/clause.test.ts b/ts/src/core/clause.test.ts index e6e437e55..17e73f6aa 100644 --- a/ts/src/core/clause.test.ts +++ b/ts/src/core/clause.test.ts @@ -13,6 +13,7 @@ describe("postgres", () => { const cls = clause.Eq("id", 4); expect(cls.clause(1)).toBe("id = $1"); expect(cls.clause(2)).toBe("id = $2"); + expect(cls.columns()).toStrictEqual(["id"]); expect(cls.values()).toStrictEqual([4]); expect(cls.logValues()).toStrictEqual([4]); expect(cls.instanceKey()).toEqual("id=4"); @@ -22,6 +23,7 @@ describe("postgres", () => { const cls = clause.Eq("id", clause.sensitiveValue(4)); expect(cls.clause(1)).toBe("id = $1"); expect(cls.clause(2)).toBe("id = $2"); + expect(cls.columns()).toStrictEqual(["id"]); expect(cls.values()).toStrictEqual([4]); expect(cls.logValues()).toStrictEqual(["*"]); expect(cls.instanceKey()).toEqual("id=4"); @@ -33,6 +35,7 @@ describe("postgres", () => { const cls = clause.NotEq("id", 4); expect(cls.clause(1)).toBe("id != $1"); expect(cls.clause(2)).toBe("id != $2"); + expect(cls.columns()).toStrictEqual(["id"]); expect(cls.values()).toStrictEqual([4]); expect(cls.logValues()).toStrictEqual([4]); expect(cls.instanceKey()).toEqual("id!=4"); @@ -42,6 +45,7 @@ describe("postgres", () => { const cls = clause.NotEq("id", clause.sensitiveValue(4)); expect(cls.clause(1)).toBe("id != $1"); expect(cls.clause(2)).toBe("id != $2"); + expect(cls.columns()).toStrictEqual(["id"]); expect(cls.values()).toStrictEqual([4]); expect(cls.logValues()).toStrictEqual(["*"]); expect(cls.instanceKey()).toEqual("id!=4"); @@ -53,6 +57,7 @@ describe("postgres", () => { const cls = clause.Greater("id", 4); expect(cls.clause(1)).toBe("id > $1"); expect(cls.clause(2)).toBe("id > $2"); + expect(cls.columns()).toStrictEqual(["id"]); expect(cls.values()).toStrictEqual([4]); expect(cls.logValues()).toStrictEqual([4]); expect(cls.instanceKey()).toEqual("id>4"); @@ -62,6 +67,7 @@ describe("postgres", () => { const cls = clause.Greater("id", clause.sensitiveValue(4)); expect(cls.clause(1)).toBe("id > $1"); expect(cls.clause(2)).toBe("id > $2"); + expect(cls.columns()).toStrictEqual(["id"]); expect(cls.values()).toStrictEqual([4]); expect(cls.logValues()).toStrictEqual(["*"]); expect(cls.instanceKey()).toEqual("id>4"); @@ -73,6 +79,7 @@ describe("postgres", () => { const cls = clause.Less("id", 4); expect(cls.clause(1)).toBe("id < $1"); expect(cls.clause(2)).toBe("id < $2"); + expect(cls.columns()).toStrictEqual(["id"]); expect(cls.values()).toStrictEqual([4]); expect(cls.logValues()).toStrictEqual([4]); expect(cls.instanceKey()).toEqual("id<4"); @@ -82,6 +89,7 @@ describe("postgres", () => { const cls = clause.Less("id", clause.sensitiveValue(4)); expect(cls.clause(1)).toBe("id < $1"); expect(cls.clause(2)).toBe("id < $2"); + expect(cls.columns()).toStrictEqual(["id"]); expect(cls.values()).toStrictEqual([4]); expect(cls.logValues()).toStrictEqual(["*"]); expect(cls.instanceKey()).toEqual("id<4"); @@ -93,6 +101,7 @@ describe("postgres", () => { const cls = clause.GreaterEq("id", 4); expect(cls.clause(1)).toBe("id >= $1"); expect(cls.clause(2)).toBe("id >= $2"); + expect(cls.columns()).toStrictEqual(["id"]); expect(cls.values()).toStrictEqual([4]); expect(cls.logValues()).toStrictEqual([4]); expect(cls.instanceKey()).toEqual("id>=4"); @@ -102,6 +111,7 @@ describe("postgres", () => { const cls = clause.GreaterEq("id", clause.sensitiveValue(4)); expect(cls.clause(1)).toBe("id >= $1"); expect(cls.clause(2)).toBe("id >= $2"); + expect(cls.columns()).toStrictEqual(["id"]); expect(cls.values()).toStrictEqual([4]); expect(cls.logValues()).toStrictEqual(["*"]); expect(cls.instanceKey()).toEqual("id>=4"); @@ -113,6 +123,7 @@ describe("postgres", () => { const cls = clause.LessEq("id", 4); expect(cls.clause(1)).toBe("id <= $1"); expect(cls.clause(2)).toBe("id <= $2"); + expect(cls.columns()).toStrictEqual(["id"]); expect(cls.values()).toStrictEqual([4]); expect(cls.logValues()).toStrictEqual([4]); expect(cls.instanceKey()).toEqual("id<=4"); @@ -122,6 +133,7 @@ describe("postgres", () => { const cls = clause.LessEq("id", clause.sensitiveValue(4)); expect(cls.clause(1)).toBe("id <= $1"); expect(cls.clause(2)).toBe("id <= $2"); + expect(cls.columns()).toStrictEqual(["id"]); expect(cls.values()).toStrictEqual([4]); expect(cls.logValues()).toStrictEqual(["*"]); expect(cls.instanceKey()).toEqual("id<=4"); @@ -132,6 +144,7 @@ describe("postgres", () => { test("2 items", () => { const cls = clause.And(clause.Eq("id1", "iddd"), clause.Eq("id2", "foo")); expect(cls.clause(1)).toBe("id1 = $1 AND id2 = $2"); + expect(cls.columns()).toStrictEqual(["id1", "id2"]); expect(cls.values()).toStrictEqual(["iddd", "foo"]); expect(cls.logValues()).toStrictEqual(["iddd", "foo"]); expect(cls.instanceKey()).toEqual("id1=iddd AND id2=foo"); @@ -144,6 +157,7 @@ describe("postgres", () => { clause.Eq("id3", "baz"), ); expect(cls.clause(1)).toBe("id1 = $1 AND id2 = $2 AND id3 = $3"); + expect(cls.columns()).toStrictEqual(["id1", "id2", "id3"]); expect(cls.values()).toStrictEqual(["iddd", "foo", "baz"]); expect(cls.logValues()).toStrictEqual(["iddd", "foo", "baz"]); expect(cls.instanceKey()).toEqual("id1=iddd AND id2=foo AND id3=baz"); @@ -156,6 +170,7 @@ describe("postgres", () => { clause.Eq("id3", "baz"), ); expect(cls.clause(1)).toBe("id1 = $1 AND id2 = $2 AND id3 = $3"); + expect(cls.columns()).toStrictEqual(["id1", "id2", "id3"]); expect(cls.values()).toStrictEqual(["iddd", "foo", "baz"]); expect(cls.logValues()).toStrictEqual(["iddd", "***", "baz"]); expect(cls.instanceKey()).toEqual("id1=iddd AND id2=foo AND id3=baz"); @@ -167,6 +182,7 @@ describe("postgres", () => { clause.Eq("id3", "baz"), ); expect(cls.clause(1)).toBe("id1 = $1 AND id2 = $2 AND id3 = $3"); + expect(cls.columns()).toStrictEqual(["id1", "id2", "id3"]); expect(cls.values()).toStrictEqual(["iddd", "foo", "baz"]); expect(cls.logValues()).toStrictEqual(["iddd", "foo", "baz"]); expect(cls.instanceKey()).toEqual("id1=iddd AND id2=foo AND id3=baz"); @@ -178,6 +194,7 @@ describe("postgres", () => { clause.And(clause.Eq("id2", "foo"), clause.Eq("id3", "baz")), ); expect(cls.clause(1)).toBe("id1 = $1 AND id2 = $2 AND id3 = $3"); + expect(cls.columns()).toStrictEqual(["id1", "id2", "id3"]); expect(cls.values()).toStrictEqual(["iddd", "foo", "baz"]); expect(cls.logValues()).toStrictEqual(["iddd", "foo", "baz"]); expect(cls.instanceKey()).toEqual("id1=iddd AND id2=foo AND id3=baz"); @@ -192,6 +209,7 @@ describe("postgres", () => { ), ); expect(cls.clause(1)).toBe("id1 = $1 AND id2 = $2 AND id3 = $3"); + expect(cls.columns()).toStrictEqual(["id1", "id2", "id3"]); expect(cls.values()).toStrictEqual(["iddd", "foo", "baz"]); expect(cls.logValues()).toStrictEqual(["iddd", "foo", "***"]); expect(cls.instanceKey()).toEqual("id1=iddd AND id2=foo AND id3=baz"); @@ -202,6 +220,7 @@ describe("postgres", () => { test("2 items", () => { const cls = clause.Or(clause.Eq("id1", "iddd"), clause.Eq("id2", "foo")); expect(cls.clause(1)).toBe("id1 = $1 OR id2 = $2"); + expect(cls.columns()).toStrictEqual(["id1", "id2"]); expect(cls.values()).toStrictEqual(["iddd", "foo"]); expect(cls.logValues()).toStrictEqual(["iddd", "foo"]); expect(cls.instanceKey()).toEqual("id1=iddd OR id2=foo"); @@ -214,6 +233,7 @@ describe("postgres", () => { clause.Eq("id3", "baz"), ); expect(cls.clause(1)).toBe("id1 = $1 OR id2 = $2 OR id3 = $3"); + expect(cls.columns()).toStrictEqual(["id1", "id2", "id3"]); expect(cls.values()).toStrictEqual(["iddd", "foo", "baz"]); expect(cls.logValues()).toStrictEqual(["iddd", "foo", "baz"]); expect(cls.instanceKey()).toEqual("id1=iddd OR id2=foo OR id3=baz"); @@ -226,6 +246,7 @@ describe("postgres", () => { clause.Eq("id3", "baz"), ); expect(cls.clause(1)).toBe("id1 = $1 OR id2 = $2 OR id3 = $3"); + expect(cls.columns()).toStrictEqual(["id1", "id2", "id3"]); expect(cls.values()).toStrictEqual(["iddd", "foo", "baz"]); expect(cls.logValues()).toStrictEqual(["iddd", "***", "baz"]); expect(cls.instanceKey()).toEqual("id1=iddd OR id2=foo OR id3=baz"); @@ -237,6 +258,7 @@ describe("postgres", () => { clause.Eq("id3", "baz"), ); expect(cls.clause(1)).toBe("id1 = $1 OR id2 = $2 OR id3 = $3"); + expect(cls.columns()).toStrictEqual(["id1", "id2", "id3"]); expect(cls.values()).toStrictEqual(["iddd", "foo", "baz"]); expect(cls.logValues()).toStrictEqual(["iddd", "foo", "baz"]); expect(cls.instanceKey()).toEqual("id1=iddd OR id2=foo OR id3=baz"); @@ -248,6 +270,7 @@ describe("postgres", () => { clause.Or(clause.Eq("id2", "foo"), clause.Eq("id3", "baz")), ); expect(cls.clause(1)).toBe("id1 = $1 OR id2 = $2 OR id3 = $3"); + expect(cls.columns()).toStrictEqual(["id1", "id2", "id3"]); expect(cls.values()).toStrictEqual(["iddd", "foo", "baz"]); expect(cls.logValues()).toStrictEqual(["iddd", "foo", "baz"]); expect(cls.instanceKey()).toEqual("id1=iddd OR id2=foo OR id3=baz"); @@ -262,6 +285,7 @@ describe("postgres", () => { ), ); expect(cls.clause(1)).toBe("id1 = $1 OR id2 = $2 OR id3 = $3"); + expect(cls.columns()).toStrictEqual(["id1", "id2", "id3"]); expect(cls.values()).toStrictEqual(["iddd", "foo", "baz"]); expect(cls.logValues()).toStrictEqual(["iddd", "foo", "***"]); expect(cls.instanceKey()).toEqual("id1=iddd OR id2=foo OR id3=baz"); @@ -274,6 +298,7 @@ describe("postgres", () => { test("spread args", () => { const cls = clause.In("id", 1, 2, 3); expect(cls.clause(1)).toBe("id IN ($1, $2, $3)"); + expect(cls.columns()).toStrictEqual(["id"]); expect(cls.values()).toStrictEqual([1, 2, 3]); expect(cls.logValues()).toStrictEqual([1, 2, 3]); expect(cls.instanceKey()).toEqual("in:id:1,2,3"); @@ -282,6 +307,7 @@ describe("postgres", () => { test("spread args with sensitive value", () => { const cls = clause.In("id", 1, 2, clause.sensitiveValue(3)); expect(cls.clause(1)).toBe("id IN ($1, $2, $3)"); + expect(cls.columns()).toStrictEqual(["id"]); expect(cls.values()).toStrictEqual([1, 2, 3]); expect(cls.logValues()).toStrictEqual([1, 2, "*"]); expect(cls.instanceKey()).toEqual("in:id:1,2,3"); @@ -290,6 +316,7 @@ describe("postgres", () => { test("list", () => { const cls = clause.In("id", ...[1, 2, 3]); expect(cls.clause(1)).toBe("id IN ($1, $2, $3)"); + expect(cls.columns()).toStrictEqual(["id"]); expect(cls.values()).toStrictEqual([1, 2, 3]); expect(cls.logValues()).toStrictEqual([1, 2, 3]); expect(cls.instanceKey()).toEqual("in:id:1,2,3"); @@ -298,6 +325,7 @@ describe("postgres", () => { test("list with sensitive value", () => { const cls = clause.In("id", ...[1, clause.sensitiveValue(2), 3]); expect(cls.clause(1)).toBe("id IN ($1, $2, $3)"); + expect(cls.columns()).toStrictEqual(["id"]); expect(cls.values()).toStrictEqual([1, 2, 3]); expect(cls.logValues()).toStrictEqual([1, "*", 3]); expect(cls.instanceKey()).toEqual("in:id:1,2,3"); @@ -308,6 +336,7 @@ describe("postgres", () => { test("eq", () => { const cls = clause.ArrayEq("ids", 3); expect(cls.clause(1)).toBe("$1 = ANY(ids)"); + expect(cls.columns()).toStrictEqual(["ids"]); expect(cls.values()).toStrictEqual([3]); expect(cls.logValues()).toStrictEqual([3]); expect(cls.instanceKey()).toEqual("ids=3"); @@ -316,64 +345,72 @@ describe("postgres", () => { test("ne", () => { const cls = clause.ArrayNotEq("ids", 3); expect(cls.clause(1)).toBe("$1 != ANY(ids)"); + expect(cls.columns()).toStrictEqual(["ids"]); expect(cls.values()).toStrictEqual([3]); expect(cls.logValues()).toStrictEqual([3]); expect(cls.instanceKey()).toEqual("ids!=3"); }); - }); - test("contains val", () => { - const cls = clause.PostgresArrayContainsValue("ids", 3); - expect(cls.clause(1)).toBe("ids @> $1"); - expect(cls.values()).toStrictEqual([`{3}`]); - expect(cls.logValues()).toStrictEqual([3]); - expect(cls.instanceKey()).toEqual("ids@>3"); - }); + test("contains val", () => { + const cls = clause.PostgresArrayContainsValue("ids", 3); + expect(cls.clause(1)).toBe("ids @> $1"); + expect(cls.columns()).toStrictEqual(["ids"]); + expect(cls.values()).toStrictEqual([`{3}`]); + expect(cls.logValues()).toStrictEqual([3]); + expect(cls.instanceKey()).toEqual("ids@>3"); + }); - test("contains val:string", () => { - const cls = clause.PostgresArrayContainsValue("ids", "foo"); - expect(cls.clause(1)).toBe("ids @> $1"); - expect(cls.values()).toStrictEqual([`{foo}`]); - expect(cls.logValues()).toStrictEqual(["foo"]); - expect(cls.instanceKey()).toEqual("ids@>foo"); - }); + test("contains val:string", () => { + const cls = clause.PostgresArrayContainsValue("ids", "foo"); + expect(cls.clause(1)).toBe("ids @> $1"); + expect(cls.columns()).toStrictEqual(["ids"]); + expect(cls.values()).toStrictEqual([`{foo}`]); + expect(cls.logValues()).toStrictEqual(["foo"]); + expect(cls.instanceKey()).toEqual("ids@>foo"); + }); - test("contains list", () => { - const cls = clause.PostgresArrayContains("ids", [3, 4]); - expect(cls.clause(1)).toBe("ids @> $1"); - expect(cls.values()).toStrictEqual([`{3, 4}`]); - expect(cls.logValues()).toStrictEqual([[3, 4]]); - expect(cls.instanceKey()).toEqual("ids@>3,4"); - }); + test("contains list", () => { + const cls = clause.PostgresArrayContains("ids", [3, 4]); + expect(cls.clause(1)).toBe("ids @> $1"); + expect(cls.columns()).toStrictEqual(["ids"]); + expect(cls.values()).toStrictEqual([`{3, 4}`]); + expect(cls.logValues()).toStrictEqual([[3, 4]]); + expect(cls.instanceKey()).toEqual("ids@>3,4"); + }); - test("contains list string", () => { - const cls = clause.PostgresArrayContains("ids", ["foo", "bar"]); - expect(cls.clause(1)).toBe("ids @> $1"); - expect(cls.values()).toStrictEqual([`{foo, bar}`]); - expect(cls.logValues()).toStrictEqual([["foo", "bar"]]); - expect(cls.instanceKey()).toEqual("ids@>foo,bar"); - }); + test("contains list string", () => { + const cls = clause.PostgresArrayContains("ids", ["foo", "bar"]); + expect(cls.clause(1)).toBe("ids @> $1"); + expect(cls.columns()).toStrictEqual(["ids"]); + expect(cls.values()).toStrictEqual([`{foo, bar}`]); + expect(cls.logValues()).toStrictEqual([["foo", "bar"]]); + expect(cls.instanceKey()).toEqual("ids@>foo,bar"); + }); - test("not contains val", () => { - const cls = clause.PostgresArrayNotContainsValue("ids", 3); - expect(cls.clause(1)).toBe("NOT ids @> $1"); - expect(cls.values()).toStrictEqual([`{3}`]); - expect(cls.logValues()).toStrictEqual([3]); - expect(cls.instanceKey()).toEqual("NOT:ids@>3"); - }); + test("not contains val", () => { + const cls = clause.PostgresArrayNotContainsValue("ids", 3); + expect(cls.clause(1)).toBe("NOT ids @> $1"); + expect(cls.columns()).toStrictEqual(["ids"]); + expect(cls.values()).toStrictEqual([`{3}`]); + expect(cls.logValues()).toStrictEqual([3]); + expect(cls.instanceKey()).toEqual("NOT:ids@>3"); + }); - test("not contains list", () => { - const cls = clause.PostgresArrayNotContains("ids", [3, 4]); - expect(cls.clause(1)).toBe("NOT ids @> $1"); - expect(cls.values()).toStrictEqual([`{3, 4}`]); - expect(cls.logValues()).toStrictEqual([[3, 4]]); - expect(cls.instanceKey()).toEqual("NOT:ids@>3,4"); + test("not contains list", () => { + const cls = clause.PostgresArrayNotContains("ids", [3, 4]); + expect(cls.clause(1)).toBe("NOT ids @> $1"); + expect(cls.columns()).toStrictEqual(["ids"]); + expect(cls.values()).toStrictEqual([`{3, 4}`]); + expect(cls.logValues()).toStrictEqual([[3, 4]]); + expect(cls.instanceKey()).toEqual("NOT:ids@>3,4"); + }); }); describe("full text", () => { test("tsquery string", () => { const cls = clause.TsQuery("name_idx", "value"); expect(cls.clause(1)).toBe("name_idx @@ to_tsquery('english', $1)"); + expect(cls.columns()).toStrictEqual(["name_idx"]); expect(cls.values()).toStrictEqual(["value"]); expect(cls.logValues()).toStrictEqual(["value"]); expect(cls.instanceKey()).toEqual("name_idx@@to_tsquery:english:value"); @@ -385,6 +422,7 @@ describe("postgres", () => { value: "value", }); expect(cls.clause(1)).toBe("name_idx @@ to_tsquery('simple', $1)"); + expect(cls.columns()).toStrictEqual(["name_idx"]); expect(cls.values()).toStrictEqual(["value"]); expect(cls.logValues()).toStrictEqual(["value"]); expect(cls.instanceKey()).toEqual("name_idx@@to_tsquery:simple:value"); @@ -393,6 +431,7 @@ describe("postgres", () => { test("plainto_tsquery string", () => { const cls = clause.PlainToTsQuery("name_idx", "value"); expect(cls.clause(1)).toBe("name_idx @@ plainto_tsquery('english', $1)"); + expect(cls.columns()).toStrictEqual(["name_idx"]); expect(cls.values()).toStrictEqual(["value"]); expect(cls.logValues()).toStrictEqual(["value"]); expect(cls.instanceKey()).toEqual( @@ -406,6 +445,7 @@ describe("postgres", () => { value: "value", }); expect(cls.clause(1)).toBe("name_idx @@ plainto_tsquery('simple', $1)"); + expect(cls.columns()).toStrictEqual(["name_idx"]); expect(cls.values()).toStrictEqual(["value"]); expect(cls.logValues()).toStrictEqual(["value"]); expect(cls.instanceKey()).toEqual( @@ -416,6 +456,7 @@ describe("postgres", () => { test("phraseto_tsquery string", () => { const cls = clause.PhraseToTsQuery("name_idx", "value"); expect(cls.clause(1)).toBe("name_idx @@ phraseto_tsquery('english', $1)"); + expect(cls.columns()).toStrictEqual(["name_idx"]); expect(cls.values()).toStrictEqual(["value"]); expect(cls.logValues()).toStrictEqual(["value"]); expect(cls.instanceKey()).toEqual( @@ -429,6 +470,7 @@ describe("postgres", () => { value: "value", }); expect(cls.clause(1)).toBe("name_idx @@ phraseto_tsquery('simple', $1)"); + expect(cls.columns()).toStrictEqual(["name_idx"]); expect(cls.values()).toStrictEqual(["value"]); expect(cls.logValues()).toStrictEqual(["value"]); expect(cls.instanceKey()).toEqual( @@ -441,6 +483,7 @@ describe("postgres", () => { expect(cls.clause(1)).toBe( "name_idx @@ websearch_to_tsquery('english', $1)", ); + expect(cls.columns()).toStrictEqual(["name_idx"]); expect(cls.values()).toStrictEqual(["value"]); expect(cls.logValues()).toStrictEqual(["value"]); expect(cls.instanceKey()).toEqual( @@ -456,6 +499,7 @@ describe("postgres", () => { expect(cls.clause(1)).toBe( "name_idx @@ websearch_to_tsquery('simple', $1)", ); + expect(cls.columns()).toStrictEqual(["name_idx"]); expect(cls.values()).toStrictEqual(["value"]); expect(cls.logValues()).toStrictEqual(["value"]); expect(cls.instanceKey()).toEqual( @@ -468,6 +512,7 @@ describe("postgres", () => { expect(cls.clause(1)).toBe( "to_tsvector(name_idx) @@ to_tsquery('english', $1)", ); + expect(cls.columns()).toStrictEqual(["name_idx"]); expect(cls.values()).toStrictEqual(["value"]); expect(cls.logValues()).toStrictEqual(["value"]); expect(cls.instanceKey()).toEqual( @@ -483,6 +528,7 @@ describe("postgres", () => { expect(cls.clause(1)).toBe( "to_tsvector(name_idx) @@ to_tsquery('simple', $1)", ); + expect(cls.columns()).toStrictEqual(["name_idx"]); expect(cls.values()).toStrictEqual(["value"]); expect(cls.logValues()).toStrictEqual(["value"]); expect(cls.instanceKey()).toEqual( @@ -495,6 +541,7 @@ describe("postgres", () => { expect(cls.clause(1)).toBe( "to_tsvector(name_idx) @@ plainto_tsquery('english', $1)", ); + expect(cls.columns()).toStrictEqual(["name_idx"]); expect(cls.values()).toStrictEqual(["value"]); expect(cls.logValues()).toStrictEqual(["value"]); expect(cls.instanceKey()).toEqual( @@ -510,6 +557,7 @@ describe("postgres", () => { expect(cls.clause(1)).toBe( "to_tsvector(name_idx) @@ plainto_tsquery('simple', $1)", ); + expect(cls.columns()).toStrictEqual(["name_idx"]); expect(cls.values()).toStrictEqual(["value"]); expect(cls.logValues()).toStrictEqual(["value"]); expect(cls.instanceKey()).toEqual( @@ -522,6 +570,7 @@ describe("postgres", () => { expect(cls.clause(1)).toBe( "to_tsvector(name_idx) @@ phraseto_tsquery('english', $1)", ); + expect(cls.columns()).toStrictEqual(["name_idx"]); expect(cls.values()).toStrictEqual(["value"]); expect(cls.logValues()).toStrictEqual(["value"]); expect(cls.instanceKey()).toEqual( @@ -537,6 +586,7 @@ describe("postgres", () => { expect(cls.clause(1)).toBe( "to_tsvector(name_idx) @@ phraseto_tsquery('simple', $1)", ); + expect(cls.columns()).toStrictEqual(["name_idx"]); expect(cls.values()).toStrictEqual(["value"]); expect(cls.logValues()).toStrictEqual(["value"]); expect(cls.instanceKey()).toEqual( @@ -549,6 +599,7 @@ describe("postgres", () => { expect(cls.clause(1)).toBe( "to_tsvector(name_idx) @@ websearch_to_tsquery('english', $1)", ); + expect(cls.columns()).toStrictEqual(["name_idx"]); expect(cls.values()).toStrictEqual(["value"]); expect(cls.logValues()).toStrictEqual(["value"]); expect(cls.instanceKey()).toEqual( @@ -564,6 +615,7 @@ describe("postgres", () => { expect(cls.clause(1)).toBe( "to_tsvector(name_idx) @@ websearch_to_tsquery('simple', $1)", ); + expect(cls.columns()).toStrictEqual(["name_idx"]); expect(cls.values()).toStrictEqual(["value"]); expect(cls.logValues()).toStrictEqual(["value"]); expect(cls.instanceKey()).toEqual( @@ -585,6 +637,7 @@ describe("sqlite", () => { const cls = clause.Eq("id", 4); expect(cls.clause(1)).toBe("id = ?"); expect(cls.clause(2)).toBe("id = ?"); + expect(cls.columns()).toStrictEqual(["id"]); expect(cls.values()).toStrictEqual([4]); expect(cls.logValues()).toStrictEqual([4]); expect(cls.instanceKey()).toEqual("id=4"); @@ -594,6 +647,7 @@ describe("sqlite", () => { const cls = clause.Eq("id", clause.sensitiveValue(4)); expect(cls.clause(1)).toBe("id = ?"); expect(cls.clause(2)).toBe("id = ?"); + expect(cls.columns()).toStrictEqual(["id"]); expect(cls.values()).toStrictEqual([4]); expect(cls.logValues()).toStrictEqual(["*"]); expect(cls.instanceKey()).toEqual("id=4"); @@ -605,6 +659,7 @@ describe("sqlite", () => { const cls = clause.Greater("id", 4); expect(cls.clause(1)).toBe("id > ?"); expect(cls.clause(2)).toBe("id > ?"); + expect(cls.columns()).toStrictEqual(["id"]); expect(cls.values()).toStrictEqual([4]); expect(cls.logValues()).toStrictEqual([4]); expect(cls.instanceKey()).toEqual("id>4"); @@ -614,6 +669,7 @@ describe("sqlite", () => { const cls = clause.Greater("id", clause.sensitiveValue(4)); expect(cls.clause(1)).toBe("id > ?"); expect(cls.clause(2)).toBe("id > ?"); + expect(cls.columns()).toStrictEqual(["id"]); expect(cls.values()).toStrictEqual([4]); expect(cls.logValues()).toStrictEqual(["*"]); expect(cls.instanceKey()).toEqual("id>4"); @@ -625,6 +681,7 @@ describe("sqlite", () => { const cls = clause.Less("id", 4); expect(cls.clause(1)).toBe("id < ?"); expect(cls.clause(2)).toBe("id < ?"); + expect(cls.columns()).toStrictEqual(["id"]); expect(cls.values()).toStrictEqual([4]); expect(cls.logValues()).toStrictEqual([4]); expect(cls.instanceKey()).toEqual("id<4"); @@ -634,6 +691,7 @@ describe("sqlite", () => { const cls = clause.Less("id", clause.sensitiveValue(4)); expect(cls.clause(1)).toBe("id < ?"); expect(cls.clause(2)).toBe("id < ?"); + expect(cls.columns()).toStrictEqual(["id"]); expect(cls.values()).toStrictEqual([4]); expect(cls.logValues()).toStrictEqual(["*"]); expect(cls.instanceKey()).toEqual("id<4"); @@ -645,6 +703,7 @@ describe("sqlite", () => { const cls = clause.GreaterEq("id", 4); expect(cls.clause(1)).toBe("id >= ?"); expect(cls.clause(2)).toBe("id >= ?"); + expect(cls.columns()).toStrictEqual(["id"]); expect(cls.values()).toStrictEqual([4]); expect(cls.logValues()).toStrictEqual([4]); expect(cls.instanceKey()).toEqual("id>=4"); @@ -654,6 +713,7 @@ describe("sqlite", () => { const cls = clause.GreaterEq("id", clause.sensitiveValue(4)); expect(cls.clause(1)).toBe("id >= ?"); expect(cls.clause(2)).toBe("id >= ?"); + expect(cls.columns()).toStrictEqual(["id"]); expect(cls.values()).toStrictEqual([4]); expect(cls.logValues()).toStrictEqual(["*"]); expect(cls.instanceKey()).toEqual("id>=4"); @@ -665,6 +725,7 @@ describe("sqlite", () => { const cls = clause.LessEq("id", 4); expect(cls.clause(1)).toBe("id <= ?"); expect(cls.clause(2)).toBe("id <= ?"); + expect(cls.columns()).toStrictEqual(["id"]); expect(cls.values()).toStrictEqual([4]); expect(cls.logValues()).toStrictEqual([4]); expect(cls.instanceKey()).toEqual("id<=4"); @@ -674,6 +735,7 @@ describe("sqlite", () => { const cls = clause.LessEq("id", clause.sensitiveValue(4)); expect(cls.clause(1)).toBe("id <= ?"); expect(cls.clause(2)).toBe("id <= ?"); + expect(cls.columns()).toStrictEqual(["id"]); expect(cls.values()).toStrictEqual([4]); expect(cls.logValues()).toStrictEqual(["*"]); expect(cls.instanceKey()).toEqual("id<=4"); @@ -684,6 +746,7 @@ describe("sqlite", () => { test("2 items", () => { const cls = clause.And(clause.Eq("id1", "iddd"), clause.Eq("id2", "foo")); expect(cls.clause(1)).toBe("id1 = ? AND id2 = ?"); + expect(cls.columns()).toStrictEqual(["id1", "id2"]); expect(cls.values()).toStrictEqual(["iddd", "foo"]); expect(cls.logValues()).toStrictEqual(["iddd", "foo"]); expect(cls.instanceKey()).toEqual("id1=iddd AND id2=foo"); @@ -696,6 +759,7 @@ describe("sqlite", () => { clause.Eq("id3", "baz"), ); expect(cls.clause(1)).toBe("id1 = ? AND id2 = ? AND id3 = ?"); + expect(cls.columns()).toStrictEqual(["id1", "id2", "id3"]); expect(cls.values()).toStrictEqual(["iddd", "foo", "baz"]); expect(cls.logValues()).toStrictEqual(["iddd", "foo", "baz"]); expect(cls.instanceKey()).toEqual("id1=iddd AND id2=foo AND id3=baz"); @@ -708,6 +772,7 @@ describe("sqlite", () => { clause.Eq("id3", "baz"), ); expect(cls.clause(1)).toBe("id1 = ? AND id2 = ? AND id3 = ?"); + expect(cls.columns()).toStrictEqual(["id1", "id2", "id3"]); expect(cls.values()).toStrictEqual(["iddd", "foo", "baz"]); expect(cls.logValues()).toStrictEqual(["iddd", "***", "baz"]); expect(cls.instanceKey()).toEqual("id1=iddd AND id2=foo AND id3=baz"); @@ -719,6 +784,7 @@ describe("sqlite", () => { clause.Eq("id3", "baz"), ); expect(cls.clause(1)).toBe("id1 = ? AND id2 = ? AND id3 = ?"); + expect(cls.columns()).toStrictEqual(["id1", "id2", "id3"]); expect(cls.values()).toStrictEqual(["iddd", "foo", "baz"]); expect(cls.logValues()).toStrictEqual(["iddd", "foo", "baz"]); expect(cls.instanceKey()).toEqual("id1=iddd AND id2=foo AND id3=baz"); @@ -730,6 +796,7 @@ describe("sqlite", () => { clause.And(clause.Eq("id2", "foo"), clause.Eq("id3", "baz")), ); expect(cls.clause(1)).toBe("id1 = ? AND id2 = ? AND id3 = ?"); + expect(cls.columns()).toStrictEqual(["id1", "id2", "id3"]); expect(cls.values()).toStrictEqual(["iddd", "foo", "baz"]); expect(cls.logValues()).toStrictEqual(["iddd", "foo", "baz"]); expect(cls.instanceKey()).toEqual("id1=iddd AND id2=foo AND id3=baz"); @@ -744,6 +811,7 @@ describe("sqlite", () => { ), ); expect(cls.clause(1)).toBe("id1 = ? AND id2 = ? AND id3 = ?"); + expect(cls.columns()).toStrictEqual(["id1", "id2", "id3"]); expect(cls.values()).toStrictEqual(["iddd", "foo", "baz"]); expect(cls.logValues()).toStrictEqual(["iddd", "foo", "***"]); expect(cls.instanceKey()).toEqual("id1=iddd AND id2=foo AND id3=baz"); @@ -754,6 +822,7 @@ describe("sqlite", () => { test("2 items", () => { const cls = clause.Or(clause.Eq("id1", "iddd"), clause.Eq("id2", "foo")); expect(cls.clause(1)).toBe("id1 = ? OR id2 = ?"); + expect(cls.columns()).toStrictEqual(["id1", "id2"]); expect(cls.values()).toStrictEqual(["iddd", "foo"]); expect(cls.logValues()).toStrictEqual(["iddd", "foo"]); expect(cls.instanceKey()).toEqual("id1=iddd OR id2=foo"); @@ -766,6 +835,7 @@ describe("sqlite", () => { clause.Eq("id3", "baz"), ); expect(cls.clause(1)).toBe("id1 = ? OR id2 = ? OR id3 = ?"); + expect(cls.columns()).toStrictEqual(["id1", "id2", "id3"]); expect(cls.values()).toStrictEqual(["iddd", "foo", "baz"]); expect(cls.logValues()).toStrictEqual(["iddd", "foo", "baz"]); expect(cls.instanceKey()).toEqual("id1=iddd OR id2=foo OR id3=baz"); @@ -778,6 +848,7 @@ describe("sqlite", () => { clause.Eq("id3", "baz"), ); expect(cls.clause(1)).toBe("id1 = ? OR id2 = ? OR id3 = ?"); + expect(cls.columns()).toStrictEqual(["id1", "id2", "id3"]); expect(cls.values()).toStrictEqual(["iddd", "foo", "baz"]); expect(cls.logValues()).toStrictEqual(["iddd", "***", "baz"]); expect(cls.instanceKey()).toEqual("id1=iddd OR id2=foo OR id3=baz"); @@ -789,6 +860,7 @@ describe("sqlite", () => { clause.Eq("id3", "baz"), ); expect(cls.clause(1)).toBe("id1 = ? OR id2 = ? OR id3 = ?"); + expect(cls.columns()).toStrictEqual(["id1", "id2", "id3"]); expect(cls.values()).toStrictEqual(["iddd", "foo", "baz"]); expect(cls.logValues()).toStrictEqual(["iddd", "foo", "baz"]); expect(cls.instanceKey()).toEqual("id1=iddd OR id2=foo OR id3=baz"); @@ -800,6 +872,7 @@ describe("sqlite", () => { clause.Or(clause.Eq("id2", "foo"), clause.Eq("id3", "baz")), ); expect(cls.clause(1)).toBe("id1 = ? OR id2 = ? OR id3 = ?"); + expect(cls.columns()).toStrictEqual(["id1", "id2", "id3"]); expect(cls.values()).toStrictEqual(["iddd", "foo", "baz"]); expect(cls.logValues()).toStrictEqual(["iddd", "foo", "baz"]); expect(cls.instanceKey()).toEqual("id1=iddd OR id2=foo OR id3=baz"); @@ -814,6 +887,7 @@ describe("sqlite", () => { ), ); expect(cls.clause(1)).toBe("id1 = ? OR id2 = ? OR id3 = ?"); + expect(cls.columns()).toStrictEqual(["id1", "id2", "id3"]); expect(cls.values()).toStrictEqual(["iddd", "foo", "baz"]); expect(cls.logValues()).toStrictEqual(["iddd", "foo", "***"]); expect(cls.instanceKey()).toEqual("id1=iddd OR id2=foo OR id3=baz"); @@ -826,6 +900,7 @@ describe("sqlite", () => { test("spread args", () => { const cls = clause.In("id", 1, 2, 3); expect(cls.clause(1)).toBe("id IN (?, ?, ?)"); + expect(cls.columns()).toStrictEqual(["id"]); expect(cls.values()).toStrictEqual([1, 2, 3]); expect(cls.logValues()).toStrictEqual([1, 2, 3]); expect(cls.instanceKey()).toEqual("in:id:1,2,3"); @@ -834,6 +909,7 @@ describe("sqlite", () => { test("spread args with sensitive value", () => { const cls = clause.In("id", 1, 2, clause.sensitiveValue(3)); expect(cls.clause(1)).toBe("id IN (?, ?, ?)"); + expect(cls.columns()).toStrictEqual(["id"]); expect(cls.values()).toStrictEqual([1, 2, 3]); expect(cls.logValues()).toStrictEqual([1, 2, "*"]); expect(cls.instanceKey()).toEqual("in:id:1,2,3"); @@ -842,6 +918,7 @@ describe("sqlite", () => { test("list", () => { const cls = clause.In("id", ...[1, 2, 3]); expect(cls.clause(1)).toBe("id IN (?, ?, ?)"); + expect(cls.columns()).toStrictEqual(["id"]); expect(cls.values()).toStrictEqual([1, 2, 3]); expect(cls.logValues()).toStrictEqual([1, 2, 3]); expect(cls.instanceKey()).toEqual("in:id:1,2,3"); @@ -850,6 +927,7 @@ describe("sqlite", () => { test("list with sensitive value", () => { const cls = clause.In("id", ...[1, clause.sensitiveValue(2), 3]); expect(cls.clause(1)).toBe("id IN (?, ?, ?)"); + expect(cls.columns()).toStrictEqual(["id"]); expect(cls.values()).toStrictEqual([1, 2, 3]); expect(cls.logValues()).toStrictEqual([1, "*", 3]); expect(cls.instanceKey()).toEqual("in:id:1,2,3"); diff --git a/ts/src/core/clause.ts b/ts/src/core/clause.ts index 99a8362a4..b5d6dcc01 100644 --- a/ts/src/core/clause.ts +++ b/ts/src/core/clause.ts @@ -4,6 +4,7 @@ import DB, { Dialect } from "./db"; export interface Clause { clause(idx: number): string; + columns(): string[]; values(): any[]; instanceKey(): string; // values to log when querying @@ -35,13 +36,13 @@ class simpleClause implements Clause { protected col: string, private value: any, private op: string, - private handleSqliteNull?: Clause, + private handleNull?: Clause, ) {} clause(idx: number): string { - const sqliteClause = this.sqliteNull(); - if (sqliteClause) { - return sqliteClause.clause(idx); + const nullClause = this.nullClause(); + if (nullClause) { + return nullClause.clause(idx); } if (DB.getDialect() === Dialect.Postgres) { return `${this.col} ${this.op} $${idx}`; @@ -49,18 +50,19 @@ class simpleClause implements Clause { return `${this.col} ${this.op} ?`; } - private sqliteNull() { - if (!this.handleSqliteNull || this.value !== null) { - return; - } - if (DB.getDialect() !== Dialect.SQLite) { + private nullClause() { + if (!this.handleNull || this.value !== null) { return; } - return this.handleSqliteNull; + return this.handleNull; + } + + columns(): string[] { + return [this.col]; } values(): any[] { - const sqliteClause = this.sqliteNull(); + const sqliteClause = this.nullClause(); if (sqliteClause) { return sqliteClause.values(); } @@ -71,7 +73,7 @@ class simpleClause implements Clause { } logValues(): any[] { - const sqliteClause = this.sqliteNull(); + const sqliteClause = this.nullClause(); if (sqliteClause) { return sqliteClause.logValues(); } @@ -82,7 +84,7 @@ class simpleClause implements Clause { } instanceKey(): string { - const sqliteClause = this.sqliteNull(); + const sqliteClause = this.nullClause(); if (sqliteClause) { return sqliteClause.instanceKey(); } @@ -97,6 +99,10 @@ class isNullClause implements Clause { return `${this.col} IS NULL`; } + columns(): string[] { + return []; + } + values(): any[] { return []; } @@ -117,6 +123,10 @@ class isNotNullClause implements Clause { return `${this.col} IS NOT NULL`; } + columns(): string[] { + return []; + } + values(): any[] { return []; } @@ -140,6 +150,10 @@ class arraySimpleClause implements Clause { return `${this.col} ${this.op} ?`; } + columns(): string[] { + return [this.col]; + } + values(): any[] { if (isSensitive(this.value)) { return [this.value.value()]; @@ -176,6 +190,10 @@ class postgresArrayContains implements Clause { throw new Error(`not supported`); } + columns(): string[] { + return [this.col]; + } + values(): any[] { if (isSensitive(this.value)) { return [`{${this.value.value()}}`]; @@ -242,6 +260,10 @@ class inClause implements Clause { // here's what sqlx does: https://play.golang.org/p/vPzvYqeAcP0 } + columns(): string[] { + return [this.col]; + } + values(): any[] { const result: any[] = []; for (const value of this.value) { @@ -283,6 +305,14 @@ class compositeClause implements Clause { return clauses.join(this.sep); } + columns(): string[] { + const ret: string[] = []; + for (const cls of this.clauses) { + ret.push(...cls.columns()); + } + return ret; + } + values(): any[] { let result = []; for (const clause of this.clauses) { @@ -326,6 +356,7 @@ class tsQueryClause implements Clause { value: this.val, }; } + clause(idx: number): string { const { language } = this.getInfo(); if (Dialect.Postgres === DB.getDialect()) { @@ -340,6 +371,10 @@ class tsQueryClause implements Clause { return `${this.col} @@ ${this.getFunction()}('${language}', ?)`; } + columns(): string[] { + return [this.col]; + } + values(): any[] { const { value } = this.getInfo(); return [value]; diff --git a/ts/src/core/config.ts b/ts/src/core/config.ts index 63d701d6e..65d6d7ad7 100644 --- a/ts/src/core/config.ts +++ b/ts/src/core/config.ts @@ -42,6 +42,10 @@ export interface Config { // the path should be relative to the root // this is hopefully a temporary solution... customGraphQLJSONPath?: string; + + // defaults to __global__schema.ts if not provided + // relative to src/schema for now + globalSchemaPath?: string; } interface CodegenConfig { @@ -106,7 +110,10 @@ interface CodegenConfig { // default is on_demand fieldPrivacyEvaluated?: fieldPrivacyEvaluated; - templatizedViewer?: templatizedViewer; + templatizedViewer?: importedObject; + + // if you want a new base class for AssocEdge e.g. to get extra data stored in custom assoc table + customAssocEdgePath?: importedObject; } interface PrettierConfig { @@ -123,9 +130,10 @@ interface PrivacyConfig { class?: boolean; } -interface templatizedViewer { +interface importedObject { path: string; name: string; + alias?: string; } function setConfig(cfg: Config) { diff --git a/ts/src/core/db.test.ts b/ts/src/core/db.test.ts index 39a0fe5db..9d9996cb0 100644 --- a/ts/src/core/db.test.ts +++ b/ts/src/core/db.test.ts @@ -6,7 +6,7 @@ import { setupSqlite, timestamp, bool, -} from "../testutils/db/test_db"; +} from "../testutils/db/temp_db"; import { createRowForTest, deleteRowsForTest, @@ -57,16 +57,13 @@ describe("sqlite", () => { tableName: "users", }); - await editRowForTest( - { - fields: { - bar: "bar2", - }, - tableName: "users", - key: "id", + await editRowForTest({ + fields: { + bar: "bar2", }, - 1, - ); + tableName: "users", + whereClause: clause.Eq("id", 1), + }); const r = await DB.getInstance() .getPool() diff --git a/ts/src/core/db_clause.test.ts b/ts/src/core/db_clause.test.ts index f17f51c65..51fea20d0 100644 --- a/ts/src/core/db_clause.test.ts +++ b/ts/src/core/db_clause.test.ts @@ -1,5 +1,5 @@ import { Dialect } from "./db"; -import { table, text, uuidList, TempDB, uuid } from "../testutils/db/test_db"; +import { table, text, uuidList, TempDB, uuid } from "../testutils/db/temp_db"; import { createRowForTest } from "../testutils/write"; import { loadConfig } from "./config"; import { loadRows } from "./ent"; diff --git a/ts/src/core/db_postgres_parallel.test.ts b/ts/src/core/db_postgres_parallel.test.ts index 7c9260634..a6fa1a004 100644 --- a/ts/src/core/db_postgres_parallel.test.ts +++ b/ts/src/core/db_postgres_parallel.test.ts @@ -1,5 +1,5 @@ import DB, { Dialect } from "./db"; -import { integer, table, text, TempDB } from "../testutils/db/test_db"; +import { integer, table, text, TempDB } from "../testutils/db/temp_db"; import { createRowForTest } from "../testutils/write"; import { loadConfig } from "./config"; diff --git a/ts/src/core/db_postgres_sequential.test.ts b/ts/src/core/db_postgres_sequential.test.ts index 167f82768..c2ee71231 100644 --- a/ts/src/core/db_postgres_sequential.test.ts +++ b/ts/src/core/db_postgres_sequential.test.ts @@ -1,5 +1,5 @@ import { Dialect } from "./db"; -import { integer, table, text, TempDB } from "../testutils/db/test_db"; +import { integer, table, text, TempDB } from "../testutils/db/temp_db"; import { createRowForTest } from "../testutils/write"; import { loadConfig } from "./config"; import { loadRow } from "./ent"; diff --git a/ts/src/core/ent.test.ts b/ts/src/core/ent.test.ts index 5b8f46143..8f67eeee5 100644 --- a/ts/src/core/ent.test.ts +++ b/ts/src/core/ent.test.ts @@ -32,7 +32,7 @@ import { setupSqlite, assoc_edge_config_table, assoc_edge_table, -} from "../testutils/db/test_db"; +} from "../testutils/db/temp_db"; jest.mock("pg"); QueryRecorder.mockPool(Pool); diff --git a/ts/src/core/ent.ts b/ts/src/core/ent.ts index ee1a75012..fdcb7ae07 100644 --- a/ts/src/core/ent.ts +++ b/ts/src/core/ent.ts @@ -35,6 +35,12 @@ import { WriteOperation, Builder } from "../action"; import { log, logEnabled, logTrace } from "./logger"; import DataLoader from "dataloader"; import { ObjectLoader } from "./loaders"; +import { + getStorageKey, + GlobalSchema, + SQLStatementOperation, + TransformedEdgeUpdateOperation, +} from "../schema/"; // TODO kill this and createDataLoader class cacheMap { @@ -675,6 +681,7 @@ export interface EditNodeOptions extends EditRowOptions { fieldsToResolve: string[]; loadEntOptions: LoadEntOptions; placeholderID?: ID; + key: string; } export class EditNodeOperation implements DataOperation { @@ -728,12 +735,7 @@ export class EditNodeOperation implements DataOperation { if (this.hasData(options.fields)) { // even this with returning * may not always work if transformed... // we can have a transformed flag to see if it should be returned? - this.row = await editRow( - queryer, - options, - this.existingEnt.id, - "RETURNING *", - ); + this.row = await editRow(queryer, options, "RETURNING *"); } else { // @ts-ignore this.row = this.existingEnt["data"]; @@ -785,7 +787,7 @@ export class EditNodeOperation implements DataOperation { }; if (this.existingEnt) { if (this.hasData(this.options.fields)) { - editRowSync(queryer, options, this.existingEnt.id, "RETURNING *"); + editRowSync(queryer, options, "RETURNING *"); this.reloadRow(queryer, this.existingEnt.id, options); } else { // @ts-ignore @@ -817,9 +819,24 @@ interface EdgeOperationOptions { dataPlaceholder?: boolean; } +let globalSchema: GlobalSchema | undefined; +export function setGlobalSchema(val: GlobalSchema) { + globalSchema = val; +} + +export function clearGlobalSchema() { + globalSchema = undefined; +} + +// used by tests. no guarantee will always exist +export function __hasGlobalSchema() { + return globalSchema !== undefined; +} + export class EdgeOperation implements DataOperation { private edgeData: AssocEdgeData | undefined; private constructor( + private builder: Builder, public edgeInput: AssocEdgeInput, private options: EdgeOperationOptions, ) {} @@ -887,7 +904,35 @@ export class EdgeOperation implements DataOperation { edge: AssocEdgeInput, context?: Context, ) { + let transformed: TransformedEdgeUpdateOperation | null = null; + let op = SQLStatementOperation.Delete; + let updateData: Data | null = null; + + // TODO respect disableTransformations + if (globalSchema?.transformEdgeWrite) { + transformed = globalSchema.transformEdgeWrite({ + op: SQLStatementOperation.Delete, + edge, + }); + if (transformed) { + op = transformed.op; + if (transformed.op === SQLStatementOperation.Insert) { + throw new Error(`cannot currently transform a delete into an insert`); + } + if (transformed.op === SQLStatementOperation.Update) { + if (!transformed.data) { + throw new Error( + `cannot transform a delete into an update without providing data`, + ); + } + updateData = transformed.data; + } + } + } + return { + op, + updateData, options: { tableName: edgeData.edgeTable, context, @@ -907,7 +952,18 @@ export class EdgeOperation implements DataOperation { context?: Context, ): Promise { const params = this.getDeleteRowParams(edgeData, edge, context); - return deleteRows(q, params.options, params.clause); + if (params.op === SQLStatementOperation.Delete) { + return deleteRows(q, params.options, params.clause); + } else { + if (params.op !== SQLStatementOperation.Update) { + throw new Error(`invalid operation ${params.op}`); + } + await editRow(q, { + tableName: params.options.tableName, + whereClause: params.clause, + fields: params.updateData!, + }); + } } private performDeleteWriteSync( @@ -917,7 +973,18 @@ export class EdgeOperation implements DataOperation { context?: Context, ): void { const params = this.getDeleteRowParams(edgeData, edge, context); - return deleteRowsSync(q, params.options, params.clause); + if (params.op === SQLStatementOperation.Delete) { + return deleteRowsSync(q, params.options, params.clause); + } else { + if (params.op !== SQLStatementOperation.Update) { + throw new Error(`invalid operation ${params.op}`); + } + editRowSync(q, { + tableName: params.options.tableName, + whereClause: params.clause, + fields: params.updateData!, + }); + } } private getInsertRowParams( @@ -941,6 +1008,34 @@ export class EdgeOperation implements DataOperation { fields["time"] = new Date().toISOString(); } + const onConflictFields = ["data"]; + + if (globalSchema?.extraEdgeFields) { + for (const name in globalSchema.extraEdgeFields) { + const f = globalSchema.extraEdgeFields[name]; + if (f.defaultValueOnCreate) { + const storageKey = getStorageKey(f, name); + fields[storageKey] = f.defaultValueOnCreate(this.builder, {}); + // onconflict make sure we override the default values + // e.g. setting deleted_at = null for soft delete + onConflictFields.push(storageKey); + } + } + } + + // TODO respect disableTransformations + + let transformed: TransformedEdgeUpdateOperation | null = null; + if (globalSchema?.transformEdgeWrite) { + transformed = globalSchema.transformEdgeWrite({ + op: SQLStatementOperation.Insert, + edge, + }); + if (transformed) { + throw new Error(`transforming an insert edge not currently supported`); + } + } + return [ { tableName: edgeData.edgeTable, @@ -948,7 +1043,9 @@ export class EdgeOperation implements DataOperation { fieldsToLog: fields, context, }, - "ON CONFLICT(id1, edge_type, id2) DO UPDATE SET data = EXCLUDED.data", + `ON CONFLICT(id1, edge_type, id2) DO UPDATE SET ${onConflictFields + .map((f) => `${f} = EXCLUDED.${f}`) + .join(", ")}`, ]; } @@ -962,6 +1059,7 @@ export class EdgeOperation implements DataOperation { await createRow(q, options, suffix); } + private performInsertWriteSync( q: SyncQueryer, edgeData: AssocEdgeData, @@ -1020,6 +1118,7 @@ export class EdgeOperation implements DataOperation { symmetricEdge(): EdgeOperation { return new EdgeOperation( + this.builder, { id1: this.edgeInput.id2, id1Type: this.edgeInput.id2Type, @@ -1040,6 +1139,7 @@ export class EdgeOperation implements DataOperation { inverseEdge(edgeData: AssocEdgeData): EdgeOperation { return new EdgeOperation( + this.builder, { id1: this.edgeInput.id2, id1Type: this.edgeInput.id2Type, @@ -1128,7 +1228,7 @@ export class EdgeOperation implements DataOperation { edge.data = data; } - return new EdgeOperation(edge, { + return new EdgeOperation(builder, edge, { operation: WriteOperation.Insert, id2Placeholder, id1Placeholder, @@ -1159,7 +1259,7 @@ export class EdgeOperation implements DataOperation { edge.data = data; } - return new EdgeOperation(edge, { + return new EdgeOperation(builder, edge, { operation: WriteOperation.Insert, id1Placeholder, id2Placeholder, @@ -1182,7 +1282,7 @@ export class EdgeOperation implements DataOperation { id2Type: "", // these 2 shouldn't matter id1Type: "", }; - return new EdgeOperation(edge, { + return new EdgeOperation(builder, edge, { operation: WriteOperation.Delete, }); } @@ -1202,7 +1302,7 @@ export class EdgeOperation implements DataOperation { id2Type: "", // these 2 shouldn't matter id1Type: "", }; - return new EdgeOperation(edge, { + return new EdgeOperation(builder, edge, { operation: WriteOperation.Delete, }); } @@ -1332,7 +1432,6 @@ export function createRowSync( export function buildUpdateQuery( options: EditRowOptions, - id: ID, suffix?: string, ): [string, any[], any[]] { let valsString: string[] = []; @@ -1342,27 +1441,30 @@ export function buildUpdateQuery( let idx = 1; for (const key in options.fields) { - values.push(options.fields[key]); + const val = options.fields[key]; + values.push(val); if (options.fieldsToLog) { logValues.push(options.fieldsToLog[key]); } + // TODO would be nice to use clause here. need update version of the queries so that + // we don't have to handle dialect specifics here + // can't use clause because of IS NULL + // valsString.push(clause.Eq(key, val).clause(idx)); if (dialect === Dialect.Postgres) { valsString.push(`${key} = $${idx}`); - idx++; } else { valsString.push(`${key} = ?`); } + idx++; } const vals = valsString.join(", "); let query = `UPDATE ${options.tableName} SET ${vals} WHERE `; - if (dialect === Dialect.Postgres) { - query = query + `${options.key} = $${idx}`; - } else { - query = query + `${options.key} = ?`; - } + query = query + options.whereClause.clause(idx); + values.push(...options.whereClause.values()); + if (suffix) { query = query + " " + suffix; } @@ -1373,13 +1475,9 @@ export function buildUpdateQuery( export async function editRow( queryer: Queryer, options: EditRowOptions, - id: ID, suffix?: string, ): Promise { - const [query, values, logValues] = buildUpdateQuery(options, id, suffix); - - // add id as value to prepared query - values.push(id); + const [query, values, logValues] = buildUpdateQuery(options, suffix); const res = await mutateRow(queryer, query, values, logValues, options); @@ -1395,13 +1493,9 @@ export async function editRow( export function editRowSync( queryer: SyncQueryer, options: EditRowOptions, - id: ID, suffix?: string, ): Data | null { - const [query, values, logValues] = buildUpdateQuery(options, id, suffix); - - // add id as value to prepared query - values.push(id); + const [query, values, logValues] = buildUpdateQuery(options, suffix); const res = mutateRowSync(queryer, query, values, logValues, options); @@ -1461,6 +1555,8 @@ export class AssocEdge { time: Date; data?: string | null; + private rawData: Data; + constructor(data: Data) { this.id1 = data.id1; this.id1Type = data.id1_type; @@ -1469,6 +1565,13 @@ export class AssocEdge { this.edgeType = data.edge_type; this.time = data.time; this.data = data.data; + this.rawData = data; + } + + __getRawData() { + // incase there's extra db fields. useful for tests + // in production, a subclass of this should be in use so we won't need this... + return this.rawData; } getCursor(): string { @@ -1606,6 +1709,7 @@ interface loadEdgesOptions { edgeType: string; context?: Context; queryOptions?: EdgeQueryableDataOptions; + disableTransformations?: boolean; } interface loadCustomEdgesOptions extends loadEdgesOptions { @@ -1632,6 +1736,25 @@ export async function loadEdges( return loadCustomEdges({ ...options, ctr: AssocEdge }); } +export function getEdgeClauseAndFields( + cls: clause.Clause, + options: loadEdgesOptions, +) { + let fields = edgeFields; + + if (globalSchema?.transformEdgeRead) { + const transformClause = globalSchema.transformEdgeRead(); + if (!options.disableTransformations) { + cls = clause.And(cls, transformClause); + } + fields = edgeFields.concat(transformClause.columns()); + } + return { + cls, + fields, + }; +} + export async function loadCustomEdges( options: loadCustomEdgesOptions, ): Promise { @@ -1646,10 +1769,13 @@ export async function loadCustomEdges( if (options.queryOptions?.clause) { cls = clause.And(cls, options.queryOptions.clause); } + + const { cls: actualClause, fields } = getEdgeClauseAndFields(cls, options); + const rows = await loadRows({ tableName: edgeData.edgeTable, - fields: edgeFields, - clause: cls, + fields: fields, + clause: actualClause, orderby: options.queryOptions?.orderby || defaultOptions.orderby, limit: options.queryOptions?.limit || defaultOptions.limit, context, @@ -1668,10 +1794,15 @@ export async function loadUniqueEdge( if (!edgeData) { throw new Error(`error loading edge data for ${edgeType}`); } + const { cls, fields } = getEdgeClauseAndFields( + clause.And(clause.Eq("id1", id1), clause.Eq("edge_type", edgeType)), + options, + ); + const row = await loadRow({ tableName: edgeData.edgeTable, - fields: edgeFields, - clause: clause.And(clause.Eq("id1", id1), clause.Eq("edge_type", edgeType)), + fields: fields, + clause: cls, context, }); if (!row) { @@ -1709,11 +1840,15 @@ export async function loadRawEdgeCountX( throw new Error(`error loading edge data for ${edgeType}`); } + const { cls } = getEdgeClauseAndFields( + clause.And(clause.Eq("id1", id1), clause.Eq("edge_type", edgeType)), + options, + ); const row = await loadRowX({ tableName: edgeData.edgeTable, // sqlite needs as count otherwise it returns count(1) fields: ["count(1) as count"], - clause: clause.And(clause.Eq("id1", id1), clause.Eq("edge_type", edgeType)), + clause: cls, context, }); return parseInt(row["count"], 10) || 0; diff --git a/ts/src/core/ent_complex.test.ts b/ts/src/core/ent_complex.test.ts index 02606c005..8d775908c 100644 --- a/ts/src/core/ent_complex.test.ts +++ b/ts/src/core/ent_complex.test.ts @@ -28,7 +28,7 @@ import { assoc_edge_table, getSchemaTable, TempDB, -} from "../testutils/db/test_db"; +} from "../testutils/db/temp_db"; import { Dialect } from "./db"; import { LoggedOutViewer } from "./viewer"; import { WriteOperation } from "../action"; diff --git a/ts/src/core/ent_custom_data.test.ts b/ts/src/core/ent_custom_data.test.ts index f3cad0c24..6d9740dbf 100644 --- a/ts/src/core/ent_custom_data.test.ts +++ b/ts/src/core/ent_custom_data.test.ts @@ -19,7 +19,7 @@ import { Pool } from "pg"; import { ContextCache } from "./context"; import * as clause from "./clause"; -import { integer, table, text, setupSqlite } from "../testutils/db/test_db"; +import { integer, table, text, setupSqlite } from "../testutils/db/temp_db"; import { MockLogs } from "../testutils/mock_log"; import { clearLogLevels, setLogLevels } from "./logger"; diff --git a/ts/src/core/ent_data.test.ts b/ts/src/core/ent_data.test.ts index 88eba5fd8..90b64dc0f 100644 --- a/ts/src/core/ent_data.test.ts +++ b/ts/src/core/ent_data.test.ts @@ -28,7 +28,7 @@ import DB from "./db"; import each from "jest-each"; import { ObjectLoaderFactory } from "./loaders"; -import { integer, table, text, setupSqlite } from "../testutils/db/test_db"; +import { integer, table, text, setupSqlite } from "../testutils/db/temp_db"; import { MockLogs } from "../testutils/mock_log"; import { clearLogLevels, setLogLevels } from "./logger"; @@ -1329,7 +1329,7 @@ function commonTests() { options = { fields: fields, fieldsToLog: fields, - key: "bar", + whereClause: clause.Eq("bar", 1), tableName: selectOptions.tableName, context: ctx!, // reuse "global" context }; @@ -1367,18 +1367,15 @@ function commonTests() { options2.fields = { ...options.fields, baz: "baz3" }; options2.fieldsToLog = options2.fields; // we need a different row so that querying after still returns one row - return editRowForTest(options2, 1); + return editRowForTest(options2); }, () => { - const [query, _, logValues] = buildUpdateQuery( - { - fields: { ...fields, baz: "baz3" }, - fieldsToLog: { ...fields, baz: "baz3" }, - tableName: selectOptions.tableName, - key: "bar", - }, - 1, - ); + const [query, _, logValues] = buildUpdateQuery({ + fields: { ...fields, baz: "baz3" }, + fieldsToLog: { ...fields, baz: "baz3" }, + tableName: selectOptions.tableName, + whereClause: clause.Eq("bar", 1), + }); return { query, values: logValues }; }, ], diff --git a/ts/src/core/ent_logs.test.ts b/ts/src/core/ent_logs.test.ts index e35bd49b4..7a3aca73b 100644 --- a/ts/src/core/ent_logs.test.ts +++ b/ts/src/core/ent_logs.test.ts @@ -27,7 +27,7 @@ import { LoadRowOptions, LoadRowsOptions, } from "./base"; -import { integer, table, text, setupSqlite } from "../testutils/db/test_db"; +import { integer, table, text, setupSqlite } from "../testutils/db/temp_db"; jest.mock("pg"); QueryRecorder.mockPool(Pool); @@ -146,11 +146,11 @@ function commonTests() { }; const options: EditRowOptions = { fields: fields, - key: "id", tableName: "t1", + whereClause: clause.Eq("id", "1"), }; - await editRowForTest(options, "1"); - const [expQuery] = buildUpdateQuery(options, "1"); + await editRowForTest(options); + const [expQuery] = buildUpdateQuery(options); expect(ml.logs.length).toEqual(1); expect(ml.logs[0]).toStrictEqual({ @@ -166,12 +166,12 @@ function commonTests() { }; const options: EditRowOptions = { fields: fields, - key: "id", tableName: "t1", fieldsToLog: fields, + whereClause: clause.Eq("id", "1"), }; - await editRowForTest(options, "1"); - const [expQuery] = buildUpdateQuery(options, "1"); + await editRowForTest(options); + const [expQuery] = buildUpdateQuery(options); expect(ml.logs.length).toEqual(1); expect(ml.logs[0]).toStrictEqual({ @@ -187,15 +187,15 @@ function commonTests() { }; const options: EditRowOptions = { fields: fields, - key: "id", tableName: "t1", + whereClause: clause.Eq("id", "1"), fieldsToLog: { col1: "bar", col2: "***", }, }; - await editRowForTest(options, "1"); - const [expQuery] = buildUpdateQuery(options, "1"); + await editRowForTest(options); + const [expQuery] = buildUpdateQuery(options); expect(ml.logs.length).toEqual(1); expect(ml.logs[0]).toStrictEqual({ @@ -211,13 +211,12 @@ function commonTests() { }; const options: EditRowOptions = { fields: fields, - key: "id", tableName: "t1", fieldsToLog: fields, + whereClause: clause.Eq("id", "1"), }; clearLogLevels(); - await editRowForTest(options, "1"); - const [expQuery] = buildUpdateQuery(options, "1"); + await editRowForTest(options); expect(ml.logs.length).toEqual(0); }); diff --git a/ts/src/core/loaders/assoc_count_loader.test.ts b/ts/src/core/loaders/assoc_count_loader.test.ts index 21a20aa6a..7eb166652 100644 --- a/ts/src/core/loaders/assoc_count_loader.test.ts +++ b/ts/src/core/loaders/assoc_count_loader.test.ts @@ -8,7 +8,7 @@ import { buildQuery } from "../ent"; import * as clause from "../clause"; -import { setupSqlite, TempDB } from "../../testutils/db/test_db"; +import { setupSqlite, TempDB } from "../../testutils/db/temp_db"; import { EdgeType, FakeContact } from "../../testutils/fake_data/index"; import { createAllContacts, diff --git a/ts/src/core/loaders/assoc_count_loader.ts b/ts/src/core/loaders/assoc_count_loader.ts index 1666d3de5..e5725ffb2 100644 --- a/ts/src/core/loaders/assoc_count_loader.ts +++ b/ts/src/core/loaders/assoc_count_loader.ts @@ -1,6 +1,10 @@ import DataLoader from "dataloader"; import { ID, Context, Loader, LoaderFactory } from "../base"; -import { loadEdgeData, loadRawEdgeCountX } from "../ent"; +import { + getEdgeClauseAndFields, + loadEdgeData, + loadRawEdgeCountX, +} from "../ent"; import * as clause from "../clause"; import { getLoader } from "./loader"; import { createCountDataLoader } from "./raw_count_loader"; @@ -21,11 +25,19 @@ export class AssocEdgeCountLoader implements Loader { if (!edgeData) { throw new Error(`error loading edge data for ${this.edgeType}`); } + const { cls } = getEdgeClauseAndFields( + clause.Eq("edge_type", this.edgeType), + { + // don't need this.. + id1: "1", + edgeType: this.edgeType, + }, + ); this.loader = createCountDataLoader({ tableName: edgeData.edgeTable, groupCol: "id1", - clause: clause.Eq("edge_type", this.edgeType), + clause: cls, }); return this.loader; } diff --git a/ts/src/core/loaders/assoc_edge_loader.test.ts b/ts/src/core/loaders/assoc_edge_loader.test.ts index 441504178..468c02333 100644 --- a/ts/src/core/loaders/assoc_edge_loader.test.ts +++ b/ts/src/core/loaders/assoc_edge_loader.test.ts @@ -7,7 +7,7 @@ import { AssocEdge, buildQuery, DefaultLimit } from "../ent"; import * as clause from "../clause"; import { EdgeQueryableDataOptions, ID, Loader } from "../base"; -import { setupSqlite, TempDB } from "../../testutils/db/test_db"; +import { setupSqlite, TempDB } from "../../testutils/db/temp_db"; import { FakeUser, FakeContact, diff --git a/ts/src/core/loaders/index_loader.test.ts b/ts/src/core/loaders/index_loader.test.ts index 3c1aaf2f6..71c0b47c7 100644 --- a/ts/src/core/loaders/index_loader.test.ts +++ b/ts/src/core/loaders/index_loader.test.ts @@ -7,7 +7,7 @@ import { buildQuery, DefaultLimit } from "../ent"; import * as clause from "../clause"; import { Data, EdgeQueryableDataOptions, ID, Loader } from "../base"; -import { setupSqlite, TempDB } from "../../testutils/db/test_db"; +import { setupSqlite, TempDB } from "../../testutils/db/temp_db"; import { FakeUser, FakeContact, diff --git a/ts/src/core/loaders/object_loader.test.ts b/ts/src/core/loaders/object_loader.test.ts index 3e29ecc1a..129093233 100644 --- a/ts/src/core/loaders/object_loader.test.ts +++ b/ts/src/core/loaders/object_loader.test.ts @@ -30,7 +30,7 @@ import { table, text, timestamp, -} from "../../testutils/db/test_db"; +} from "../../testutils/db/temp_db"; import DB, { Dialect } from "../db"; import { advanceTo } from "jest-date-mock"; import { convertDate } from "../convert"; @@ -197,13 +197,6 @@ describe("sqlite", () => { commonTests(); }); -function filterNullIfSqlite(values: any[]) { - if (DB.getDialect() === Dialect.SQLite) { - return values.filter((f) => f !== null); - } - return values; -} - function transformDeletedAt(row: Data | null) { if (row === null) { return null; @@ -329,7 +322,7 @@ function commonTests() { expect(ml.logs.length).toBe(1); expect(ml.logs[0]).toStrictEqual({ query: expQuery, - values: filterNullIfSqlite([null, 1]), + values: [1], }); const row2 = await loader.load(1); @@ -408,7 +401,7 @@ function commonTests() { expect(ml.logs.length).toBe(1); expect(ml.logs[0]).toStrictEqual({ query: expQuery, - values: filterNullIfSqlite([null, 1]), + values: [1], }); // same data loaded but not same row @@ -421,7 +414,7 @@ function commonTests() { expect(ml.logs.length).toBe(2); expect(ml.logs[1]).toStrictEqual({ query: expQuery, - values: filterNullIfSqlite([null, 1]), + values: [1], }); } @@ -453,7 +446,7 @@ function commonTests() { expect(ml.logs.length).toBe(1); expect(ml.logs[0]).toStrictEqual({ query: expQuery, - values: filterNullIfSqlite([null, 1]), + values: [1], }); // same data loaded but not same row @@ -465,7 +458,7 @@ function commonTests() { expect(ml.logs.length).toBe(2); expect(ml.logs[1]).toStrictEqual({ query: expQuery, - values: filterNullIfSqlite([null, 1]), + values: [1], }); } @@ -563,7 +556,7 @@ function commonTests() { expect(ml.logs.length).toBe(1); expect(ml.logs[0]).toStrictEqual({ query: expQuery, - values: filterNullIfSqlite([null, 1]), + values: [1], }); // same data loaded but not same row @@ -575,7 +568,7 @@ function commonTests() { expect(ml.logs.length).toBe(2); expect(ml.logs[1]).toStrictEqual({ query: expQuery, - values: filterNullIfSqlite([null, 1]), + values: [1], }); } @@ -716,16 +709,13 @@ function commonTests() { deleted_at: null, }); - await editRowForTest( - { - tableName: "users", - key: "id", - fields: { - deleted_at: new Date(), - }, + await editRowForTest({ + tableName: "users", + whereClause: clause.Eq("id", 1), + fields: { + deleted_at: new Date(), }, - 1, - ); + }); ctx.cache.clearCache(); const rowPostDelete = await loader.load(1); @@ -1039,7 +1029,7 @@ function verifyMultiIDsCustomClauseGroupQuery(ids: ID[]) { expect(ml.logs.length).toBe(1); expect(ml.logs[0]).toStrictEqual({ query: expQuery, - values: filterNullIfSqlite([null, ...ids]), + values: ids, }); } @@ -1071,7 +1061,7 @@ function verifyMultiIDsCustomClauseGroupQueryMiss(ids: ID[]) { }); expect(log).toStrictEqual({ query: expQuery, - values: filterNullIfSqlite([null, ids[idx]]), + values: [ids[idx]], }); }); } diff --git a/ts/src/core/loaders/query_loader.test.ts b/ts/src/core/loaders/query_loader.test.ts index 29d3b70fe..dca1ff248 100644 --- a/ts/src/core/loaders/query_loader.test.ts +++ b/ts/src/core/loaders/query_loader.test.ts @@ -4,7 +4,7 @@ import { MockLogs } from "../../testutils/mock_log"; import { buildQuery, DefaultLimit } from "../ent"; import * as clause from "../clause"; import { Data, EdgeQueryableDataOptions, ID, Loader } from "../base"; -import { setupSqlite, TempDB } from "../../testutils/db/test_db"; +import { setupSqlite, TempDB } from "../../testutils/db/temp_db"; import { FakeUser, FakeEvent, diff --git a/ts/src/core/loaders/raw_count_loader.test.ts b/ts/src/core/loaders/raw_count_loader.test.ts index 52b2e6c06..2818497a8 100644 --- a/ts/src/core/loaders/raw_count_loader.test.ts +++ b/ts/src/core/loaders/raw_count_loader.test.ts @@ -7,7 +7,7 @@ import { MockLogs } from "../../testutils/mock_log"; import { ID } from "../base"; import { buildQuery } from "../ent"; import * as clause from "../clause"; -import { setupSqlite, TempDB } from "../../testutils/db/test_db"; +import { setupSqlite, TempDB } from "../../testutils/db/temp_db"; import { FakeContact, getCompleteClause, diff --git a/ts/src/core/query/assoc_query.test.ts b/ts/src/core/query/assoc_query.test.ts index 5de613f8c..323335e1d 100644 --- a/ts/src/core/query/assoc_query.test.ts +++ b/ts/src/core/query/assoc_query.test.ts @@ -20,6 +20,7 @@ commonTests({ return UserToContactsQuery.query(viewer, user); }, tableName: "user_to_contacts_table", + uniqKey: "user_to_contacts_table", entsLength: 2, where: "id1 = $1 AND edge_type = $2", sortCol: "time", diff --git a/ts/src/core/query/assoc_query_global.test.ts b/ts/src/core/query/assoc_query_global.test.ts new file mode 100644 index 000000000..a8f5bc667 --- /dev/null +++ b/ts/src/core/query/assoc_query_global.test.ts @@ -0,0 +1,63 @@ +import { Pool } from "pg"; +import { QueryRecorder } from "../../testutils/db_mock"; +import { Viewer } from "../base"; +import { + EdgeType, + FakeUser, + UserToContactsQuery, +} from "../../testutils/fake_data/index"; +import { createEdges, inputs } from "../../testutils/fake_data/test_helpers"; +import { commonTests } from "./shared_test"; +import { assocTests } from "./shared_assoc_test"; +import { loadCustomEdges } from "../ent"; +import { EdgeWithDeletedAt } from "../../testutils/test_edge_global_schema"; +import { convertDate } from "../convert"; + +jest.mock("pg"); +QueryRecorder.mockPool(Pool); + +beforeEach(async () => { + QueryRecorder.clear(); + await createEdges(); + QueryRecorder.clearQueries(); +}); + +commonTests({ + newQuery(viewer: Viewer, user: FakeUser) { + return UserToContactsQuery.query(viewer, user); + }, + uniqKey: "user_to_contacts_table", + tableName: "user_to_contacts_table", + entsLength: 2, + where: "id1 = $1 AND edge_type = $2 AND deleted_at IS NULL", + sortCol: "time", + globalSchema: true, + rawDataVerify: async (user: FakeUser) => { + const [raw, withDeleted] = await Promise.all([ + loadCustomEdges({ + id1: user.id, + edgeType: EdgeType.UserToContacts, + ctr: EdgeWithDeletedAt, + }), + loadCustomEdges({ + id1: user.id, + edgeType: EdgeType.UserToContacts, + ctr: EdgeWithDeletedAt, + disableTransformations: true, + }), + ]); + expect(raw.length).toBe(0); + expect(withDeleted.length).toBe(inputs.length); + withDeleted.map((edge) => { + expect(edge.deletedAt).not.toBe(null); + expect(convertDate(edge.deletedAt!)).toBeInstanceOf(Date); + }); + }, +}); + +assocTests(true); + +// TODO need to figure out a better way to test time. we had ms here +// for times but we needed Date object comparions +// tests work for both but production only works with Date comparisons +// flaw with nosql parse_sql implementation diff --git a/ts/src/core/query/assoc_query_sqlite.test.ts b/ts/src/core/query/assoc_query_sqlite.test.ts index de224506e..e7a64d2f4 100644 --- a/ts/src/core/query/assoc_query_sqlite.test.ts +++ b/ts/src/core/query/assoc_query_sqlite.test.ts @@ -1,19 +1,41 @@ import { Viewer } from "../base"; -import { FakeUser, UserToContactsQuery } from "../../testutils/fake_data/index"; -import { tempDBTables } from "../../testutils/fake_data/test_helpers"; +import { + EdgeType, + FakeUser, + UserToContactsQuery, +} from "../../testutils/fake_data/index"; import { commonTests } from "./shared_test"; import { assocTests } from "./shared_assoc_test"; -import { setupSqlite } from "../../testutils/db/test_db"; +import { loadCustomEdges } from "../ent"; +import { EdgeWithDeletedAt } from "../../testutils/test_edge_global_schema"; commonTests({ newQuery(viewer: Viewer, user: FakeUser) { return UserToContactsQuery.query(viewer, user); }, tableName: "user_to_contacts_table", + uniqKey: "user_to_contacts_table_sqlite", entsLength: 2, where: "id1 = ? AND edge_type = ?", sortCol: "time", sqlite: true, + rawDataVerify: async (user: FakeUser) => { + const [raw, withDeleted] = await Promise.all([ + loadCustomEdges({ + id1: user.id, + edgeType: EdgeType.UserToContacts, + ctr: EdgeWithDeletedAt, + }), + loadCustomEdges({ + id1: user.id, + edgeType: EdgeType.UserToContacts, + ctr: EdgeWithDeletedAt, + disableTransformations: true, + }), + ]); + expect(raw.length).toBe(0); + expect(withDeleted.length).toBe(0); + }, }); describe("custom assoc", () => { diff --git a/ts/src/core/query/assoc_query_sqlite_global.test.ts b/ts/src/core/query/assoc_query_sqlite_global.test.ts new file mode 100644 index 000000000..6923063af --- /dev/null +++ b/ts/src/core/query/assoc_query_sqlite_global.test.ts @@ -0,0 +1,55 @@ +import { Viewer } from "../base"; +import { + EdgeType, + FakeUser, + UserToContactsQuery, +} from "../../testutils/fake_data/index"; +import { commonTests } from "./shared_test"; +import { assocTests } from "./shared_assoc_test"; +import { loadCustomEdges } from "../ent"; +import { EdgeWithDeletedAt } from "../../testutils/test_edge_global_schema"; +import { inputs } from "../../testutils/fake_data/test_helpers"; +import { convertDate } from "../../core/convert"; + +// deleted_at column added for this case and assoc tests should work +commonTests({ + newQuery(viewer: Viewer, user: FakeUser) { + return UserToContactsQuery.query(viewer, user); + }, + tableName: "user_to_contacts_table", + uniqKey: "user_to_contacts_table_global", + entsLength: 2, + where: "id1 = ? AND edge_type = ? AND deleted_at IS NULL", + sortCol: "time", + sqlite: true, + globalSchema: true, + rawDataVerify: async (user: FakeUser) => { + const [raw, withDeleted] = await Promise.all([ + loadCustomEdges({ + id1: user.id, + edgeType: EdgeType.UserToContacts, + ctr: EdgeWithDeletedAt, + }), + loadCustomEdges({ + id1: user.id, + edgeType: EdgeType.UserToContacts, + ctr: EdgeWithDeletedAt, + disableTransformations: true, + }), + ]); + expect(raw.length).toBe(0); + expect(withDeleted.length).toBe(inputs.length); + withDeleted.map((edge) => { + expect(edge.deletedAt).not.toBe(null); + expect(convertDate(edge.deletedAt!)).toBeInstanceOf(Date); + }); + }, +}); + +describe("custom assoc", () => { + // DB.getInstance is broken. so we need the same assoc instance to be used + // setupSqlite(`sqlite:///assoc_query_sqlite.db`, tempDBTables); + + // TODO there's a weird dependency with commonTest above where commenting that out breaks this... + assocTests(); +}); diff --git a/ts/src/core/query/complex_custom_query.test.ts b/ts/src/core/query/complex_custom_query.test.ts index 489205398..429779101 100644 --- a/ts/src/core/query/complex_custom_query.test.ts +++ b/ts/src/core/query/complex_custom_query.test.ts @@ -13,7 +13,7 @@ import { setupTempDB, } from "../../testutils/fake_data/test_helpers"; import { setLogLevels } from "../logger"; -import { TempDB } from "../../testutils/db/test_db"; +import { TempDB } from "../../testutils/db/temp_db"; import { buildQuery } from "../ent"; import * as clause from "../clause"; import { Viewer } from "../base"; diff --git a/ts/src/core/query/custom_query.test.ts b/ts/src/core/query/custom_query.test.ts index 750bbb3da..7315dc074 100644 --- a/ts/src/core/query/custom_query.test.ts +++ b/ts/src/core/query/custom_query.test.ts @@ -22,6 +22,7 @@ commonTests({ newQuery(viewer: Viewer, user: FakeUser) { return UserToContactsFkeyQuery.query(viewer, user); }, + uniqKey: "fake_contacts", tableName: "fake_contacts", where: "user_id = $1", sortCol: "created_at", diff --git a/ts/src/core/query/custom_query_live.test.ts b/ts/src/core/query/custom_query_live.test.ts index 2cb4799d3..5c1428e85 100644 --- a/ts/src/core/query/custom_query_live.test.ts +++ b/ts/src/core/query/custom_query_live.test.ts @@ -14,6 +14,7 @@ commonTests({ newQuery(viewer: Viewer, user: FakeUser) { return UserToContactsFkeyQuery.query(viewer, user); }, + uniqKey: "fake_contacts", tableName: "fake_contacts", where: "user_id = $1", sortCol: "created_at", diff --git a/ts/src/core/query/custom_query_sqlite.test.ts b/ts/src/core/query/custom_query_sqlite.test.ts index 8a4c7350c..754c2b222 100644 --- a/ts/src/core/query/custom_query_sqlite.test.ts +++ b/ts/src/core/query/custom_query_sqlite.test.ts @@ -9,6 +9,7 @@ commonTests({ newQuery(viewer: Viewer, user: FakeUser) { return UserToContactsFkeyQuery.query(viewer, user); }, + uniqKey: "fake_contacts", tableName: "fake_contacts", where: "user_id = ?", sortCol: "created_at", diff --git a/ts/src/core/query/shared_assoc_test.ts b/ts/src/core/query/shared_assoc_test.ts index eed322dfb..e7390ff4c 100644 --- a/ts/src/core/query/shared_assoc_test.ts +++ b/ts/src/core/query/shared_assoc_test.ts @@ -37,7 +37,7 @@ import { } from "../../testutils/fake_data/test_helpers"; import DB, { Dialect } from "../db"; -export function assocTests() { +export function assocTests(global = false) { describe("custom edge", () => { let user1, user2: FakeUser; @@ -112,10 +112,17 @@ export function assocTests() { for (let i = 0; i < numQueries; i++) { const query = queries[i]; let expLimit = disablePaginationBump ? limit : limit + 1; - expect(query.qs?.whereClause, `${i}`).toBe( - // default limit - `id1 = $1 AND edge_type = $2 ORDER BY time DESC LIMIT ${expLimit}`, - ); + if (global) { + expect(query.qs?.whereClause, `${i}`).toBe( + // default limit + `id1 = $1 AND edge_type = $2 AND deleted_at IS NULL ORDER BY time DESC LIMIT ${expLimit}`, + ); + } else { + expect(query.qs?.whereClause, `${i}`).toBe( + // default limit + `id1 = $1 AND edge_type = $2 ORDER BY time DESC LIMIT ${expLimit}`, + ); + } } } @@ -127,7 +134,13 @@ export function assocTests() { expect(queries.length).toBe(length); for (let i = 0; i < numQueries; i++) { const query = queries[i]; - expect(query.qs?.whereClause).toBe(`id1 = $1 AND edge_type = $2`); + if (global) { + expect(query.qs?.whereClause).toBe( + `id1 = $1 AND edge_type = $2 AND deleted_at IS NULL`, + ); + } else { + expect(query.qs?.whereClause).toBe(`id1 = $1 AND edge_type = $2`); + } } } diff --git a/ts/src/core/query/shared_test.ts b/ts/src/core/query/shared_test.ts index 10514b8f4..4bf878d91 100644 --- a/ts/src/core/query/shared_test.ts +++ b/ts/src/core/query/shared_test.ts @@ -1,11 +1,14 @@ import { QueryRecorder } from "../../testutils/db_mock"; -import { Ent, Data, ID, Viewer } from "../base"; -import { DefaultLimit, AssocEdge, getCursor } from "../ent"; +import { Data, ID, Viewer } from "../base"; +import { DefaultLimit, AssocEdge, getCursor, setGlobalSchema } from "../ent"; import { IDViewer, LoggedOutViewer } from "../viewer"; import { FakeUser, FakeContact, UserToContactsFkeyQuery, + FakeUserSchema, + EdgeType, + FakeContactSchema, } from "../../testutils/fake_data/index"; import { inputs, @@ -18,14 +21,17 @@ import { tempDBTables, } from "../../testutils/fake_data/test_helpers"; import { EdgeQuery } from "./query"; -import { setupSqlite, TempDB } from "../../testutils/db/test_db"; +import { setupSqlite, TempDB } from "../../testutils/db/temp_db"; import { TestContext } from "../../testutils/context/test_context"; import { setLogLevels } from "../logger"; +import { testEdgeGlobalSchema } from "../../testutils/test_edge_global_schema"; +import { SimpleAction } from "../../testutils/builder"; +import { WriteOperation } from "../../action"; class TestQueryFilter { - private allContacts: FakeContact[] = []; + allContacts: FakeContact[] = []; private filteredContacts: FakeContact[] = []; - private user: FakeUser; + user: FakeUser; constructor( private filter: ( q: EdgeQuery, @@ -67,22 +73,22 @@ class TestQueryFilter { } // rawCount isn't affected by filters... - async testRawCount() { + async testRawCount(expectedCount?: number) { const count = await this.getQuery().queryRawCount(); - this.verifyRawCount(count); + this.verifyRawCount(count, expectedCount); } - private verifyRawCount(count: number) { - expect(count).toBe(inputs.length); + private verifyRawCount(count: number, expectedCount?: number) { + expect(count).toBe(expectedCount ?? inputs.length); } - async testCount() { + async testCount(expectedCount?: number) { const count = await this.getQuery().queryCount(); - this.verifyCount(count); + this.verifyCount(count, expectedCount); } - private verifyCount(count: number) { - expect(count).toBe(this.filteredContacts.length); + private verifyCount(count: number, expectedCount?: number) { + expect(count).toBe(expectedCount ?? this.filteredContacts.length); } async testEdges() { @@ -114,7 +120,7 @@ class TestQueryFilter { verifyUserToContacts(this.user, ents, this.filteredContacts); } - async testAll() { + async testAll(expectedCount?: number) { const query = this.getQuery(new IDViewer(this.user.id)); const [edges, count, ids, rawCount, ents] = await Promise.all([ query.queryEdges(), @@ -123,10 +129,10 @@ class TestQueryFilter { query.queryRawCount(), query.queryEnts(), ]); - this.verifyCount(count); + this.verifyCount(count, expectedCount); this.verifyEdges(edges); this.verifyIDs(ids); - this.verifyRawCount(rawCount); + this.verifyRawCount(rawCount, expectedCount); this.verifyEnts(ents); } } @@ -139,12 +145,15 @@ interface options { user: FakeUser, ) => EdgeQuery; tableName: string; + uniqKey: string; entsLength?: number; where: string; sortCol: string; livePostgresDB?: boolean; // if livedb creates temp db and not depending on mock sqlite?: boolean; // do this in sqlite + globalSchema?: boolean; + rawDataVerify?(user: FakeUser): Promise; } export const commonTests = (opts: options) => { @@ -192,10 +201,20 @@ export const commonTests = (opts: options) => { const query = queries[0]; const result = [...opts.where.matchAll(preparedVar)]; + let parts = opts.where.split(" AND "); + if (parts[parts.length - 1] === "deleted_at IS NULL") { + parts = parts + .slice(0, parts.length - 1) + .concat([ + `${opts.sortCol} < $${result.length + 1}`, + "deleted_at IS NULL", + ]); + } else { + parts.push(`${opts.sortCol} < $${result.length + 1}`); + } + expect(query.qs?.whereClause).toBe( - `${opts.where} AND ${opts.sortCol} < $${result.length + 1} ORDER BY ${ - opts.sortCol - } DESC LIMIT 4`, + `${parts.join(" AND ")} ORDER BY ${opts.sortCol} DESC LIMIT 4`, ); } @@ -208,11 +227,21 @@ export const commonTests = (opts: options) => { const query = queries[0]; const result = [...opts.where.matchAll(preparedVar)]; + let parts = opts.where.split(" AND "); + if (parts[parts.length - 1] === "deleted_at IS NULL") { + parts = parts + .slice(0, parts.length - 1) + .concat([ + `${opts.sortCol} > $${result.length + 1}`, + "deleted_at IS NULL", + ]); + } else { + parts.push(`${opts.sortCol} > $${result.length + 1}`); + } + expect(query.qs?.whereClause).toBe( // extra fetched for pagination - `${opts.where} AND ${opts.sortCol} > $${result.length + 1} ORDER BY ${ - opts.sortCol - } ASC LIMIT 4`, + `${parts.join(" AND ")} ORDER BY ${opts.sortCol} ASC LIMIT 4`, ); } @@ -251,10 +280,15 @@ export const commonTests = (opts: options) => { }); } + if (opts.globalSchema) { + setGlobalSchema(testEdgeGlobalSchema); + } + let tdb: TempDB; if (opts.sqlite) { - // tableName just to make it unique - setupSqlite(`sqlite:///shared_test+${opts.tableName}.db`, tempDBTables); + setupSqlite(`sqlite:///shared_test+${opts.uniqKey}.db`, () => + tempDBTables(opts.globalSchema), + ); } beforeAll(async () => { @@ -281,7 +315,7 @@ export const commonTests = (opts: options) => { describe("simple queries", () => { const filter = new TestQueryFilter( (q: EdgeQuery) => { - // no filterzs + // no filters return q; }, opts.newQuery, @@ -327,6 +361,87 @@ export const commonTests = (opts: options) => { }); }); + describe("after delete", () => { + const filter = new TestQueryFilter( + (q: EdgeQuery) => { + // no filters + return q; + }, + opts.newQuery, + (contacts: FakeContact[]) => { + // nothing expected since deleted + return []; + }, + getViewer(), + ); + + beforeEach(async () => { + await filter.beforeEach(); + const action = new SimpleAction( + filter.user.viewer, + FakeUserSchema, + new Map(), + WriteOperation.Edit, + filter.user, + ); + await Promise.all( + filter.allContacts.map(async (contact) => { + action.builder.orchestrator.removeOutboundEdge( + contact.id, + EdgeType.UserToContacts, + ); + + const action2 = new SimpleAction( + filter.user.viewer, + FakeContactSchema, + new Map(), + WriteOperation.Delete, + contact, + ); + await action2.save(); + }), + ); + await action.save(); + QueryRecorder.clearQueries(); + }); + + test("ids", async () => { + await filter.testIDs(); + verifyQuery({}); + }); + + test("rawCount", async () => { + await filter.testRawCount(0); + verifyCountQuery({}); + }); + + test("count", async () => { + await filter.testCount(0); + verifyQuery({}); + }); + + test("edges", async () => { + await filter.testEdges(); + verifyQuery({}); + }); + + test("ents", async () => { + await filter.testEnts(); + // no ents so no subsequent query. just the edge query + verifyQuery({ length: 1 }); + }); + + test("all", async () => { + await filter.testAll(0); + }); + + test("raw_data", async () => { + if (opts.rawDataVerify) { + await opts.rawDataVerify(filter.user); + } + }); + }); + describe("first. no cursor", () => { const N = 2; const filter = new TestQueryFilter( diff --git a/ts/src/graphql/node_resolver.test.ts b/ts/src/graphql/node_resolver.test.ts index a412fb2c4..34f7e854e 100644 --- a/ts/src/graphql/node_resolver.test.ts +++ b/ts/src/graphql/node_resolver.test.ts @@ -45,7 +45,7 @@ import { queryRootConfig, expectQueryFromRoot, } from "../testutils/ent-graphql-tests"; -import { setupSqlite } from "../testutils/db/test_db"; +import { setupSqlite } from "../testutils/db/temp_db"; jest.mock("pg"); QueryRecorder.mockPool(Pool); diff --git a/ts/src/graphql/query/assoc_edge_connection_sqlite.test.ts b/ts/src/graphql/query/assoc_edge_connection_sqlite.test.ts index 1d9924145..d193afe67 100644 --- a/ts/src/graphql/query/assoc_edge_connection_sqlite.test.ts +++ b/ts/src/graphql/query/assoc_edge_connection_sqlite.test.ts @@ -5,7 +5,7 @@ import { } from "../../testutils/fake_data/test_helpers"; import { commonTests } from "./shared_edge_connection"; import { sharedAssocTests } from "./shared_assoc_test"; -import { setupSqlite } from "../../testutils/db/test_db"; +import { setupSqlite } from "../../testutils/db/temp_db"; beforeEach(async () => { await createEdges(); diff --git a/ts/src/graphql/query/custom_edge_connection_sqlite.test.ts b/ts/src/graphql/query/custom_edge_connection_sqlite.test.ts index 0d2e9c8fb..c6aaeaebd 100644 --- a/ts/src/graphql/query/custom_edge_connection_sqlite.test.ts +++ b/ts/src/graphql/query/custom_edge_connection_sqlite.test.ts @@ -1,4 +1,4 @@ -import { setupSqlite } from "../../testutils/db/test_db"; +import { setupSqlite } from "../../testutils/db/temp_db"; import { FakeUser, UserToContactsFkeyQuery, diff --git a/ts/src/index.ts b/ts/src/index.ts index c0b8f626b..076c11cd4 100644 --- a/ts/src/index.ts +++ b/ts/src/index.ts @@ -33,6 +33,7 @@ export { loadEdgeForID2, loadNodesByEdge, getEdgeTypeInGroup, + setGlobalSchema, } from "./core/ent"; import DB from "./core/db"; export * from "./core/loaders"; diff --git a/ts/src/parse_schema/parse.ts b/ts/src/parse_schema/parse.ts index 27029a6fa..de96923a2 100644 --- a/ts/src/parse_schema/parse.ts +++ b/ts/src/parse_schema/parse.ts @@ -6,7 +6,7 @@ import { AssocEdgeGroup, Action, } from "../schema"; -import { ActionField, Type, FieldMap } from "../schema/schema"; +import { ActionField, Type, FieldMap, GlobalSchema } from "../schema/schema"; function processFields( src: FieldMap | Field[], @@ -304,6 +304,7 @@ interface patternsDict { interface Result { schemas: schemasDict; patterns: patternsDict; + globalSchema?: ProcessedGlobalSchema; } declare type PotentialSchemas = { @@ -314,10 +315,17 @@ interface InputSchema extends Schema { schemaPath?: string; } -export function parseSchema(potentialSchemas: PotentialSchemas): Result { +export function parseSchema( + potentialSchemas: PotentialSchemas, + globalSchema?: GlobalSchema, +): Result { let schemas: schemasDict = {}; let patterns: patternsDict = {}; + let parsedGlobalSchema: ProcessedGlobalSchema | undefined; + if (globalSchema) { + parsedGlobalSchema = parseGlobalSchema(globalSchema); + } for (const key in potentialSchemas) { const value = potentialSchemas[key]; let schema: InputSchema; @@ -384,5 +392,32 @@ export function parseSchema(potentialSchemas: PotentialSchemas): Result { schemas[key] = processedSchema; } - return { schemas, patterns }; + return { schemas, patterns, globalSchema: parsedGlobalSchema }; +} + +interface ProcessedGlobalSchema { + globalEdges: ProcessedAssocEdge[]; + extraEdgeFields: ProcessedField[]; + initForEdges?: boolean; +} + +function parseGlobalSchema(s: GlobalSchema): ProcessedGlobalSchema { + const ret: ProcessedGlobalSchema = { + globalEdges: [], + extraEdgeFields: [], + initForEdges: + !!s.extraEdgeFields || + s.transformEdgeRead !== undefined || + s.transformEdgeWrite !== undefined, + }; + + if (s.extraEdgeFields) { + ret.extraEdgeFields = processFields(s.extraEdgeFields); + } + + if (s.edges) { + ret.globalEdges = processEdges(s.edges); + } + + return ret; } diff --git a/ts/src/parse_schema/parse_type.test.ts b/ts/src/parse_schema/parse_type.test.ts index e406c4bef..db5627a4d 100644 --- a/ts/src/parse_schema/parse_type.test.ts +++ b/ts/src/parse_schema/parse_type.test.ts @@ -1,4 +1,4 @@ -import { Field, DBType, FieldMap } from "../schema/schema"; +import { DBType, FieldMap } from "../schema/schema"; import { BaseEntSchema } from "../schema/base_schema"; import { parseSchema } from "./parse"; import { JSONBType, JSONBListType } from "../schema/json_field"; diff --git a/ts/src/schema/index.ts b/ts/src/schema/index.ts index effc1838f..cff4db51d 100644 --- a/ts/src/schema/index.ts +++ b/ts/src/schema/index.ts @@ -29,8 +29,11 @@ export { UpdateOperation, TransformedUpdateOperation, SQLStatementOperation, + EdgeUpdateOperation, + TransformedEdgeUpdateOperation, getTransformedReadClause, getObjectLoaderProperties, + GlobalSchema, } from "./schema"; export { Timestamps, diff --git a/ts/src/schema/postgres_schema_live.test.ts b/ts/src/schema/postgres_schema_live.test.ts index c635aba8a..4da55e5a8 100644 --- a/ts/src/schema/postgres_schema_live.test.ts +++ b/ts/src/schema/postgres_schema_live.test.ts @@ -24,7 +24,7 @@ import { timestamptz, uuid, getSchemaTable, -} from "../testutils/db/test_db"; +} from "../testutils/db/temp_db"; import { v4 as uuidv4 } from "uuid"; import pg from "pg"; import { defaultTimestampParser, Dialect } from "../core/db"; diff --git a/ts/src/schema/schema.ts b/ts/src/schema/schema.ts index 74cf22569..fd0b6c0ea 100644 --- a/ts/src/schema/schema.ts +++ b/ts/src/schema/schema.ts @@ -2,6 +2,7 @@ import { snakeCase } from "snake-case"; import { Data, Ent, LoaderInfo, PrivacyPolicy, Viewer } from "../core/base"; import { Builder } from "../action/action"; import { Clause } from "../core/clause"; +import { AssocEdgeInput } from "../core/ent"; export declare type FieldMap = { [key: string]: Field; @@ -16,6 +17,22 @@ export type FieldInfoMap = { [key: string]: FieldInfo; }; +export interface GlobalSchema { + // source is ¯\_(ツ)_/¯ + // this api works fine for external to int + // internal to external, we need to solve ala polymorphic + // internal to internal, why is this here + edges?: Edge[]; + + // e.g. deleted_at for edges + extraEdgeFields?: FieldMap; + + transformEdgeRead?: () => Clause; + transformEdgeWrite?: ( + stmt: EdgeUpdateOperation, + ) => TransformedEdgeUpdateOperation | null; +} + // Schema is the base for every schema in typescript export default interface Schema { // schema has list of fields that are unique to each node @@ -203,6 +220,18 @@ export enum SQLStatementOperation { Delete = "delete", } +export interface EdgeUpdateOperation { + op: SQLStatementOperation; + edge: AssocEdgeInput; +} + +export interface TransformedEdgeUpdateOperation { + op: SQLStatementOperation; + + // data to write to db for this edge + data?: Data; +} + export interface UpdateOperation< TEnt extends Ent, TViewer extends Viewer = Viewer, diff --git a/ts/src/schema/schema_json.test.ts b/ts/src/schema/schema_json.test.ts index e66e0e425..89e28ec64 100644 --- a/ts/src/schema/schema_json.test.ts +++ b/ts/src/schema/schema_json.test.ts @@ -2,7 +2,7 @@ import { LoggedOutViewer } from "../core/viewer"; import { Schema, Field } from "."; import { User, SimpleAction, BuilderSchema } from "../testutils/builder"; -import { TempDB, getSchemaTable } from "../testutils/db/test_db"; +import { TempDB, getSchemaTable } from "../testutils/db/temp_db"; import DB, { Dialect } from "../core/db"; import { Ent } from "../core/base"; import * as fs from "fs"; diff --git a/ts/src/schema/schema_list.test.ts b/ts/src/schema/schema_list.test.ts index 9226eedea..faf1ea5d5 100644 --- a/ts/src/schema/schema_list.test.ts +++ b/ts/src/schema/schema_list.test.ts @@ -15,7 +15,7 @@ import { import { JSONBListType, JSONListType } from "./json_field"; import Schema from "./schema"; import { User, SimpleAction, BuilderSchema } from "../testutils/builder"; -import { TempDB, getSchemaTable } from "../testutils/db/test_db"; +import { TempDB, getSchemaTable } from "../testutils/db/temp_db"; import { v4 } from "uuid"; import DB, { Dialect } from "../core/db"; import { Ent } from "../core/base"; diff --git a/ts/src/scripts/read_schema.ts b/ts/src/scripts/read_schema.ts index 9c8eee271..89d238b9a 100644 --- a/ts/src/scripts/read_schema.ts +++ b/ts/src/scripts/read_schema.ts @@ -4,6 +4,8 @@ import { pascalCase } from "pascal-case"; import minimist from "minimist"; import { exit } from "process"; import { parseSchema } from "../parse_schema/parse"; +import { getCustomInfo } from "../tsc/ast"; +import { GlobalSchema } from "../schema/schema"; function main() { const options = minimist(process.argv.slice(2)); @@ -12,13 +14,23 @@ function main() { throw new Error("path required"); } + const customInfo = getCustomInfo(); + const globalSchemaPath = customInfo.globalSchemaPath || "__global__schema.ts"; + + let globalSchema: GlobalSchema | undefined; const r = /(\w+).ts/; + // do we still even need this... const paths = glob.sync(path.join(options.path, "*.ts"), { ignore: [`\d+_read_schema.ts`], }); let potentialSchemas = {}; for (const p of paths) { const basename = path.basename(p); + if (basename === globalSchemaPath) { + globalSchema = require(p).default; + continue; + } + const match = r.exec(basename); if (!match) { throw new Error(`non-typescript file ${p} returned by glob`); @@ -41,7 +53,7 @@ function main() { } // console.log(potentialSchemas); - const result = parseSchema(potentialSchemas); + const result = parseSchema(potentialSchemas, globalSchema); console.log(JSON.stringify(result)); } diff --git a/ts/src/testutils/db/test_db.ts b/ts/src/testutils/db/temp_db.ts similarity index 95% rename from ts/src/testutils/db/test_db.ts rename to ts/src/testutils/db/temp_db.ts index 04544bd33..6289460d4 100644 --- a/ts/src/testutils/db/test_db.ts +++ b/ts/src/testutils/db/temp_db.ts @@ -8,6 +8,7 @@ import { DBType, Field, getFields } from "../../schema"; import { snakeCase } from "snake-case"; import { BuilderSchema, getTableName } from "../builder"; import { Ent } from "../../core/base"; +import { testEdgeGlobalSchema } from "../test_edge_global_schema"; interface SchemaItem { name: string; @@ -560,8 +561,10 @@ export function assoc_edge_config_table() { ); } -export function assoc_edge_table(name: string) { - return table( +// if global flag is true, add any column from testEdgeGlobalSchema +// up to caller to set/clear that as needed +export function assoc_edge_table(name: string, global?: boolean) { + const t = table( name, uuid("id1"), text("id1_type"), @@ -573,6 +576,18 @@ export function assoc_edge_table(name: string) { text("data", { nullable: true }), primaryKey(`${name}_pkey`, ["id1", "id2", "edge_type"]), ); + + if (global) { + for (const k in testEdgeGlobalSchema.extraEdgeFields) { + const col = getColumnFromField( + k, + testEdgeGlobalSchema.extraEdgeFields[k], + Dialect.Postgres, + ); + t.columns.push(col); + } + } + return t; } interface sqliteSetupOptions { @@ -583,11 +598,11 @@ export function setupSqlite( tables: () => Table[], opts?: sqliteSetupOptions, ) { - let tdb: TempDB; + let tdb: TempDB = new TempDB(Dialect.SQLite, tables()); + beforeAll(async () => { process.env.DB_CONNECTION_STRING = connString; loadConfig(); - tdb = new TempDB(Dialect.SQLite, tables()); await tdb.beforeAll(); const conn = DB.getInstance().getConnection(); @@ -614,6 +629,8 @@ export function setupSqlite( fs.rmSync(tdb.getSqliteClient().name); }); + + return tdb; } export function getSchemaTable(schema: BuilderSchema, dialect: Dialect) { @@ -666,7 +683,11 @@ function getColumnForDbType( } } -function getColumnFromField(fieldName: string, f: Field, dialect: Dialect) { +export function getColumnFromField( + fieldName: string, + f: Field, + dialect: Dialect, +) { switch (f.type.dbType) { case DBType.List: const elemType = f.type.listElemType; diff --git a/ts/src/testutils/db/test_db.test.ts b/ts/src/testutils/db/test_db.test.ts index c92c17a24..e4de3da2b 100644 --- a/ts/src/testutils/db/test_db.test.ts +++ b/ts/src/testutils/db/test_db.test.ts @@ -1,5 +1,5 @@ import { Dialect } from "../../core/db"; -import { TempDB, text, table, uuid, setupSqlite } from "./test_db"; +import { TempDB, text, table, uuid, setupSqlite } from "./temp_db"; const fkeyTables = () => { return [ diff --git a/ts/src/testutils/db/test_db_helpers.test.ts b/ts/src/testutils/db/test_db_helpers.test.ts index 43d174d5f..ec8760ad0 100644 --- a/ts/src/testutils/db/test_db_helpers.test.ts +++ b/ts/src/testutils/db/test_db_helpers.test.ts @@ -5,7 +5,7 @@ import { getSchemaName, getTableName, } from "../builder"; -import { getSchemaTable } from "./test_db"; +import { getSchemaTable } from "./temp_db"; import { Dialect } from "../../core/db"; class Account implements Ent { diff --git a/ts/src/testutils/db_mock.test.ts b/ts/src/testutils/db_mock.test.ts index a6f1a668e..4a9b7e6db 100644 --- a/ts/src/testutils/db_mock.test.ts +++ b/ts/src/testutils/db_mock.test.ts @@ -539,17 +539,14 @@ describe("ops", () => { test("AND 2 ops", async () => { await Promise.all( [4, 8].map(async (id) => { - return await editRowForTest( - { - tableName: "t", - fields: { - bar: "bar2", - baz: "baz3", - }, - key: "id", + return await editRowForTest({ + tableName: "t", + fields: { + bar: "bar2", + baz: "baz3", }, - id, - ); + whereClause: clause.Eq("id", id), + }); }), ); const rows = await loadRows({ @@ -569,17 +566,14 @@ describe("ops", () => { test("AND 3 ops", async () => { await Promise.all( [4, 8].map(async (id) => { - return await editRowForTest( - { - tableName: "t", - fields: { - bar: "bar2", - baz: "baz3", - }, - key: "id", + return await editRowForTest({ + tableName: "t", + fields: { + bar: "bar2", + baz: "baz3", }, - id, - ); + whereClause: clause.Eq("id", id), + }); }), ); const rows = await loadRows({ @@ -628,17 +622,14 @@ describe("ops", () => { test("OR 4 ops", async () => { await Promise.all( [4, 8].map(async (id) => { - return await editRowForTest( - { - tableName: "t", - fields: { - bar: "bar2", - baz: "baz3", - }, - key: "id", + return await editRowForTest({ + tableName: "t", + fields: { + bar: "bar2", + baz: "baz3", }, - id, - ); + whereClause: clause.Eq("id", id), + }); }), ); const rows = await loadRows({ @@ -669,16 +660,13 @@ describe("update", () => { }); test("simple update", async () => { - const row = await editRowForTest( - { - tableName: "t", - fields: { - bar: "bar2", - }, - key: "id", + const row = await editRowForTest({ + tableName: "t", + fields: { + bar: "bar2", }, - 1, - ); + whereClause: clause.Eq("id", 1), + }); expect(row).toBeNull(); verifyIDRowWritten({ id: 1, bar: "bar2", baz: "baz", name: "John" }, 1); }); @@ -690,9 +678,8 @@ describe("update", () => { fields: { bar: "bar2", }, - key: "id", + whereClause: clause.Eq("id", 1), }, - 1, "RETURNING *", ); expect(row).toStrictEqual({ id: 1, bar: "bar2", baz: "baz", name: "John" }); @@ -706,9 +693,8 @@ describe("update", () => { fields: { bar: "bar2", }, - key: "id", + whereClause: clause.Eq("id", 1), }, - 1, "RETURNING id, bar", ); expect(row).toStrictEqual({ id: 1, bar: "bar2" }); diff --git a/ts/src/testutils/fake_data/fake_contact.ts b/ts/src/testutils/fake_data/fake_contact.ts index 15cd01878..b6ce004e8 100644 --- a/ts/src/testutils/fake_data/fake_contact.ts +++ b/ts/src/testutils/fake_data/fake_contact.ts @@ -11,7 +11,7 @@ import { AllowIfViewerIsRule, AlwaysDenyRule } from "../../core/privacy"; import { getBuilderSchemaFromFields, SimpleBuilder } from "../builder"; import { StringType, UUIDType } from "../../schema"; import { NodeType } from "./const"; -import { table, uuid, text, timestamptz } from "../db/test_db"; +import { table, uuid, text, timestamptz } from "../db/temp_db"; import { ObjectLoaderFactory } from "../../core/loaders"; import { convertDate } from "../../core/convert"; import { WriteOperation } from "../../action"; diff --git a/ts/src/testutils/fake_data/fake_event.ts b/ts/src/testutils/fake_data/fake_event.ts index f705368f3..43a71fd3d 100644 --- a/ts/src/testutils/fake_data/fake_event.ts +++ b/ts/src/testutils/fake_data/fake_event.ts @@ -11,7 +11,7 @@ import { AlwaysAllowPrivacyPolicy } from "../../core/privacy"; import { getBuilderSchemaFromFields, SimpleBuilder } from "../builder"; import { StringType, UUIDType, TimestampType } from "../../schema"; import { NodeType } from "./const"; -import { table, uuid, text, timestamptz } from "../db/test_db"; +import { table, uuid, text, timestamptz } from "../db/temp_db"; import { ObjectLoaderFactory } from "../../core/loaders"; import { convertDate, convertNullableDate } from "../../core/convert"; import { WriteOperation } from "../../action"; diff --git a/ts/src/testutils/fake_data/fake_user.ts b/ts/src/testutils/fake_data/fake_user.ts index eb3788842..10903dc1a 100644 --- a/ts/src/testutils/fake_data/fake_user.ts +++ b/ts/src/testutils/fake_data/fake_user.ts @@ -18,7 +18,7 @@ import { StringType } from "../../schema"; import { EdgeType } from "./internal"; import { NodeType } from "./const"; import { IDViewer, IDViewerOptions } from "../../core/viewer"; -import { table, uuid, text, timestamptz } from "../db/test_db"; +import { table, uuid, text, timestamptz } from "../db/temp_db"; import { ObjectLoaderFactory } from "../../core/loaders"; import { convertDate } from "../../core/convert"; import { WriteOperation } from "../../action"; diff --git a/ts/src/testutils/fake_data/test_helpers.ts b/ts/src/testutils/fake_data/test_helpers.ts index 94a8ccba7..a0659118a 100644 --- a/ts/src/testutils/fake_data/test_helpers.ts +++ b/ts/src/testutils/fake_data/test_helpers.ts @@ -8,7 +8,7 @@ import { TempDB, assoc_edge_config_table, assoc_edge_table, -} from "../db/test_db"; +} from "../db/temp_db"; import { createUser, @@ -316,7 +316,7 @@ export async function setupTempDB() { return tdb; } -export function tempDBTables() { +export function tempDBTables(global: boolean = false) { const tables = [ FakeUser.getTestTable(), FakeContact.getTestTable(), @@ -324,7 +324,7 @@ export function tempDBTables() { assoc_edge_config_table(), ]; edgeTableNames().forEach((tableName) => - tables.push(assoc_edge_table(tableName)), + tables.push(assoc_edge_table(tableName, global)), ); return tables; diff --git a/ts/src/testutils/parse_sql.ts b/ts/src/testutils/parse_sql.ts index 39575627c..0d39889cc 100644 --- a/ts/src/testutils/parse_sql.ts +++ b/ts/src/testutils/parse_sql.ts @@ -356,6 +356,11 @@ function getOp(where: any, values: any[]): Where { case "OR": return new OrOp([getOp(where.left, values), getOp(where.right, values)]); + case "IS": + if (where.right?.value === null) { + return new EqOp(getColumnFromRef(where.left), null); + } + default: console.log(where); throw new Error(`unsupported op ${where.operator}`); diff --git a/ts/src/testutils/test_edge_global_schema.ts b/ts/src/testutils/test_edge_global_schema.ts new file mode 100644 index 000000000..27898a3ed --- /dev/null +++ b/ts/src/testutils/test_edge_global_schema.ts @@ -0,0 +1,49 @@ +import { + SQLStatementOperation, + TimestampType, + EdgeUpdateOperation, + TransformedEdgeUpdateOperation, +} from "../schema"; +import * as clause from "../core/clause"; +import { AssocEdge } from "../core/ent"; +import { Data } from "../core/base"; + +export class EdgeWithDeletedAt extends AssocEdge { + deletedAt: Date | null; + + constructor(data: Data) { + super(data); + this.deletedAt = data.deleted_at; + } +} + +export const testEdgeGlobalSchema = { + extraEdgeFields: { + // need this to be lowerCamelCase because we do this based on field name + // #510 + deletedAt: TimestampType({ + nullable: true, + index: true, + defaultValueOnCreate: () => null, + }), + }, + + transformEdgeRead(): clause.Clause { + return clause.Eq("deleted_at", null); + }, + + transformEdgeWrite( + stmt: EdgeUpdateOperation, + ): TransformedEdgeUpdateOperation | null { + switch (stmt.op) { + case SQLStatementOperation.Delete: + return { + op: SQLStatementOperation.Update, + data: { + deleted_at: new Date(), + }, + }; + } + return null; + }, +}; diff --git a/ts/src/testutils/write.ts b/ts/src/testutils/write.ts index 85f91555f..2c07445cf 100644 --- a/ts/src/testutils/write.ts +++ b/ts/src/testutils/write.ts @@ -36,18 +36,14 @@ export async function createRowForTest( } } -export async function editRowForTest( - options: EditRowOptions, - id: ID, - suffix?: string, -) { +export async function editRowForTest(options: EditRowOptions, suffix?: string) { const client = await DB.getInstance().getNewClient(); try { if (isSyncClient(client)) { - return editRowSync(client, options, id, suffix || ""); + return editRowSync(client, options, suffix || ""); } - return await editRow(client, options, id, suffix); + return await editRow(client, options, suffix); } finally { client.release(); } diff --git a/ts/src/tsc/ast.ts b/ts/src/tsc/ast.ts index 52bd3ea49..e1b8bc6a7 100644 --- a/ts/src/tsc/ast.ts +++ b/ts/src/tsc/ast.ts @@ -307,8 +307,10 @@ export interface customInfo { name: string; }; relativeImports?: boolean; + globalSchemaPath?: string; } +// also used in parse schema logic export function getCustomInfo(): customInfo { let yaml: Config | undefined = {}; @@ -326,6 +328,7 @@ export function getCustomInfo(): customInfo { return { viewerInfo: yaml.codegen.templatizedViewer, relativeImports, + globalSchemaPath: yaml.globalSchemaPath, }; } } catch (e) {} @@ -335,5 +338,6 @@ export function getCustomInfo(): customInfo { name: "Viewer", }, relativeImports, + globalSchemaPath: yaml.globalSchemaPath, }; }