From df3ee884ab387e2f2e47116553fdc3e0d68bd6d0 Mon Sep 17 00:00:00 2001 From: David Cramer Date: Fri, 12 May 2023 14:49:46 -0700 Subject: [PATCH] Add follower graph implementation --- .eslintcache | 1 - .gitignore | 3 +- .prettierignore | 1 + Makefile | 12 +- apps/api/migrations/0003_military_preak.sql | 26 + apps/api/migrations/meta/0003_snapshot.json | 736 ++++++++++++++++++ apps/api/migrations/meta/_journal.json | 9 +- apps/api/package.json | 2 +- apps/api/src/bin/load-mocks.ts | 28 +- apps/api/src/db/index.ts | 5 + apps/api/src/db/schema.ts | 28 + apps/api/src/lib/db.ts | 39 +- apps/api/src/lib/test/fixtures.ts | 33 +- apps/api/src/lib/transformers/follow.ts | 18 + apps/api/src/lib/transformers/user.ts | 6 +- apps/api/src/middleware/auth.ts | 4 +- .../{entities.test.ts => addEntity.test.ts} | 34 +- apps/api/src/routes/addTasting.test.ts | 6 +- apps/api/src/routes/getBottle.tsx | 13 +- apps/api/src/routes/getEntity.test.ts | 25 + apps/api/src/routes/getUser.test.ts | 20 + apps/api/src/routes/getUser.ts | 26 +- apps/api/src/routes/index.ts | 8 + apps/api/src/routes/listEntities.test.ts | 26 + apps/api/src/routes/listFollowers.test.ts | 53 ++ apps/api/src/routes/listFollowers.ts | 102 +++ apps/api/src/routes/listTastings.test.ts | 63 +- apps/api/src/routes/listTastings.ts | 57 +- apps/api/src/routes/listUsers.test.ts | 4 +- apps/api/src/routes/listUsers.ts | 15 +- apps/api/src/routes/updateFollower.test.ts | 68 ++ apps/api/src/routes/updateFollower.ts | 105 +++ apps/api/src/routes/updateUser.test.ts | 52 ++ apps/api/src/routes/userFollow.test.ts | 83 ++ apps/api/src/routes/userFollow.ts | 86 ++ apps/api/src/routes/userUnfollow.test.ts | 81 ++ apps/api/src/routes/userUnfollow.ts | 57 ++ apps/web/package.json | 1 + apps/web/src/components/appHeader.tsx | 36 +- apps/web/src/components/tastingListItem.tsx | 22 +- apps/web/src/components/timeSince.tsx | 15 + apps/web/src/error-page.tsx | 17 +- apps/web/src/lib/api.tsx | 5 + apps/web/src/routes.tsx | 6 + apps/web/src/routes/activity.tsx | 2 +- apps/web/src/routes/bottleDetails.tsx | 20 +- apps/web/src/routes/brandDetails.tsx | 2 +- apps/web/src/routes/editBottle.tsx | 1 - apps/web/src/routes/followers.tsx | 114 +++ apps/web/src/routes/userDetails.tsx | 28 +- apps/web/src/types.ts | 17 + apps/web/tailwind.config.js | 14 + package.json | 1 + pnpm-lock.yaml | 7 + 54 files changed, 2107 insertions(+), 136 deletions(-) delete mode 100644 .eslintcache create mode 100644 apps/api/migrations/0003_military_preak.sql create mode 100644 apps/api/migrations/meta/0003_snapshot.json create mode 100644 apps/api/src/lib/transformers/follow.ts rename apps/api/src/routes/{entities.test.ts => addEntity.test.ts} (53%) create mode 100644 apps/api/src/routes/getEntity.test.ts create mode 100644 apps/api/src/routes/listEntities.test.ts create mode 100644 apps/api/src/routes/listFollowers.test.ts create mode 100644 apps/api/src/routes/listFollowers.ts create mode 100644 apps/api/src/routes/updateFollower.test.ts create mode 100644 apps/api/src/routes/updateFollower.ts create mode 100644 apps/api/src/routes/updateUser.test.ts create mode 100644 apps/api/src/routes/userFollow.test.ts create mode 100644 apps/api/src/routes/userFollow.ts create mode 100644 apps/api/src/routes/userUnfollow.test.ts create mode 100644 apps/api/src/routes/userUnfollow.ts create mode 100644 apps/web/src/components/timeSince.tsx create mode 100644 apps/web/src/routes/followers.tsx diff --git a/.eslintcache b/.eslintcache deleted file mode 100644 index 237b47f3..00000000 --- a/.eslintcache +++ /dev/null @@ -1 +0,0 @@ -[{"/Users/dcramer/src/peated/.eslintrc.js":"1","/Users/dcramer/src/peated/apps/api/src/app.ts":"2","/Users/dcramer/src/peated/apps/api/src/bin/db.ts":"3","/Users/dcramer/src/peated/apps/api/src/bin/load-mocks.ts":"4","/Users/dcramer/src/peated/apps/api/src/bin/user.ts":"5","/Users/dcramer/src/peated/apps/api/src/config.ts":"6","/Users/dcramer/src/peated/apps/api/src/db/index.ts":"7","/Users/dcramer/src/peated/apps/api/src/db/migrate.ts":"8","/Users/dcramer/src/peated/apps/api/src/db/schema.ts":"9","/Users/dcramer/src/peated/apps/api/src/globals.d.ts":"10","/Users/dcramer/src/peated/apps/api/src/instruments.ts":"11","/Users/dcramer/src/peated/apps/api/src/lib/auth.ts":"12","/Users/dcramer/src/peated/apps/api/src/lib/db.ts":"13","/Users/dcramer/src/peated/apps/api/src/lib/filter.ts":"14","/Users/dcramer/src/peated/apps/api/src/lib/paging.test.ts":"15","/Users/dcramer/src/peated/apps/api/src/lib/paging.ts":"16","/Users/dcramer/src/peated/apps/api/src/lib/test/expects.ts":"17","/Users/dcramer/src/peated/apps/api/src/lib/test/fixtures.ts":"18","/Users/dcramer/src/peated/apps/api/src/lib/transformers/bottle.ts":"19","/Users/dcramer/src/peated/apps/api/src/lib/transformers/tasting.ts":"20","/Users/dcramer/src/peated/apps/api/src/lib/transformers/user.ts":"21","/Users/dcramer/src/peated/apps/api/src/lib/uploads.ts":"22","/Users/dcramer/src/peated/apps/api/src/middleware/auth.ts":"23","/Users/dcramer/src/peated/apps/api/src/routes/addBottle.test.ts":"24","/Users/dcramer/src/peated/apps/api/src/routes/addBottle.ts":"25","/Users/dcramer/src/peated/apps/api/src/routes/addEntity.ts":"26","/Users/dcramer/src/peated/apps/api/src/routes/addTasting.test.ts":"27","/Users/dcramer/src/peated/apps/api/src/routes/addTasting.ts":"28","/Users/dcramer/src/peated/apps/api/src/routes/authBasic.ts":"29","/Users/dcramer/src/peated/apps/api/src/routes/authDetails.ts":"30","/Users/dcramer/src/peated/apps/api/src/routes/authGoogle.ts":"31","/Users/dcramer/src/peated/apps/api/src/routes/entities.test.ts":"32","/Users/dcramer/src/peated/apps/api/src/routes/getBottle.test.ts":"33","/Users/dcramer/src/peated/apps/api/src/routes/getBottle.tsx":"34","/Users/dcramer/src/peated/apps/api/src/routes/getEntity.ts":"35","/Users/dcramer/src/peated/apps/api/src/routes/getTasting.test.ts":"36","/Users/dcramer/src/peated/apps/api/src/routes/getTasting.ts":"37","/Users/dcramer/src/peated/apps/api/src/routes/getUser.test.ts":"38","/Users/dcramer/src/peated/apps/api/src/routes/getUser.ts":"39","/Users/dcramer/src/peated/apps/api/src/routes/index.ts":"40","/Users/dcramer/src/peated/apps/api/src/routes/listBottles.test.ts":"41","/Users/dcramer/src/peated/apps/api/src/routes/listBottles.ts":"42","/Users/dcramer/src/peated/apps/api/src/routes/listEntities.ts":"43","/Users/dcramer/src/peated/apps/api/src/routes/listTastings.test.ts":"44","/Users/dcramer/src/peated/apps/api/src/routes/listTastings.ts":"45","/Users/dcramer/src/peated/apps/api/src/routes/listUsers.test.ts":"46","/Users/dcramer/src/peated/apps/api/src/routes/listUsers.ts":"47","/Users/dcramer/src/peated/apps/api/src/routes/updateBottle.test.ts":"48","/Users/dcramer/src/peated/apps/api/src/routes/updateBottle.ts":"49","/Users/dcramer/src/peated/apps/api/src/routes/updateTastingImage.ts":"50","/Users/dcramer/src/peated/apps/api/src/routes/updateUser.ts":"51","/Users/dcramer/src/peated/apps/api/src/routes/updateUserAvatar.ts":"52","/Users/dcramer/src/peated/apps/api/src/routes/uploads.ts":"53","/Users/dcramer/src/peated/apps/api/src/schemas/bottle.tsx":"54","/Users/dcramer/src/peated/apps/api/src/sentryPlugin.ts":"55","/Users/dcramer/src/peated/apps/api/src/server.ts":"56","/Users/dcramer/src/peated/apps/api/src/test/setup-test-env.ts":"57","/Users/dcramer/src/peated/apps/api/vitest.config.ts":"58","/Users/dcramer/src/peated/apps/scraper/src/api.ts":"59","/Users/dcramer/src/peated/apps/scraper/src/main.ts":"60","/Users/dcramer/src/peated/apps/scraper/src/scraper.ts":"61","/Users/dcramer/src/peated/apps/web/dev-dist/sw.js":"62","/Users/dcramer/src/peated/apps/web/dev-dist/workbox-6966ae98.js":"63","/Users/dcramer/src/peated/apps/web/dev-dist/workbox-b4947dc9.js":"64","/Users/dcramer/src/peated/apps/web/dist/assets/index.js":"65","/Users/dcramer/src/peated/apps/web/dist/assets/workbox-window.prod.es5.js":"66","/Users/dcramer/src/peated/apps/web/dist/sw.js":"67","/Users/dcramer/src/peated/apps/web/dist/workbox-d2983725.js":"68","/Users/dcramer/src/peated/apps/web/postcss.config.js":"69","/Users/dcramer/src/peated/apps/web/src/components/alert.tsx":"70","/Users/dcramer/src/peated/apps/web/src/components/appHeader.tsx":"71","/Users/dcramer/src/peated/apps/web/src/components/bottleCard.tsx":"72","/Users/dcramer/src/peated/apps/web/src/components/bottleName.tsx":"73","/Users/dcramer/src/peated/apps/web/src/components/bottleTable.tsx":"74","/Users/dcramer/src/peated/apps/web/src/components/brandField.tsx":"75","/Users/dcramer/src/peated/apps/web/src/components/brandTable.tsx":"76","/Users/dcramer/src/peated/apps/web/src/components/button.tsx":"77","/Users/dcramer/src/peated/apps/web/src/components/chip.tsx":"78","/Users/dcramer/src/peated/apps/web/src/components/countryField.tsx":"79","/Users/dcramer/src/peated/apps/web/src/components/distillerField.tsx":"80","/Users/dcramer/src/peated/apps/web/src/components/distillerTable.tsx":"81","/Users/dcramer/src/peated/apps/web/src/components/fieldset.tsx":"82","/Users/dcramer/src/peated/apps/web/src/components/floatingButton.tsx":"83","/Users/dcramer/src/peated/apps/web/src/components/formError.tsx":"84","/Users/dcramer/src/peated/apps/web/src/components/formField.tsx":"85","/Users/dcramer/src/peated/apps/web/src/components/formHeader.tsx":"86","/Users/dcramer/src/peated/apps/web/src/components/formLabel.tsx":"87","/Users/dcramer/src/peated/apps/web/src/components/header.tsx":"88","/Users/dcramer/src/peated/apps/web/src/components/helpText.tsx":"89","/Users/dcramer/src/peated/apps/web/src/components/imageField.tsx":"90","/Users/dcramer/src/peated/apps/web/src/components/layout.tsx":"91","/Users/dcramer/src/peated/apps/web/src/components/listItem.tsx":"92","/Users/dcramer/src/peated/apps/web/src/components/rating.tsx":"93","/Users/dcramer/src/peated/apps/web/src/components/ratingField.tsx":"94","/Users/dcramer/src/peated/apps/web/src/components/reloadPrompt.tsx":"95","/Users/dcramer/src/peated/apps/web/src/components/screen.tsx":"96","/Users/dcramer/src/peated/apps/web/src/components/scrollView.tsx":"97","/Users/dcramer/src/peated/apps/web/src/components/searchHeader.tsx":"98","/Users/dcramer/src/peated/apps/web/src/components/spinner.tsx":"99","/Users/dcramer/src/peated/apps/web/src/components/tagsField.tsx":"100","/Users/dcramer/src/peated/apps/web/src/components/tastingListItem.tsx":"101","/Users/dcramer/src/peated/apps/web/src/components/textArea.tsx":"102","/Users/dcramer/src/peated/apps/web/src/components/textAreaField.tsx":"103","/Users/dcramer/src/peated/apps/web/src/components/textField.tsx":"104","/Users/dcramer/src/peated/apps/web/src/components/textInput.tsx":"105","/Users/dcramer/src/peated/apps/web/src/components/userAvatar.tsx":"106","/Users/dcramer/src/peated/apps/web/src/config.tsx":"107","/Users/dcramer/src/peated/apps/web/src/error-page.tsx":"108","/Users/dcramer/src/peated/apps/web/src/hooks/useAuth.tsx":"109","/Users/dcramer/src/peated/apps/web/src/hooks/useLocalStorage.tsx":"110","/Users/dcramer/src/peated/apps/web/src/hooks/useOnlineStatus.tsx":"111","/Users/dcramer/src/peated/apps/web/src/lib/api.tsx":"112","/Users/dcramer/src/peated/apps/web/src/lib/classNames.tsx":"113","/Users/dcramer/src/peated/apps/web/src/lib/strings.tsx":"114","/Users/dcramer/src/peated/apps/web/src/main.tsx":"115","/Users/dcramer/src/peated/apps/web/src/routes/activity.tsx":"116","/Users/dcramer/src/peated/apps/web/src/routes/addBottle.tsx":"117","/Users/dcramer/src/peated/apps/web/src/routes/addTasting.tsx":"118","/Users/dcramer/src/peated/apps/web/src/routes/bottleDetails.tsx":"119","/Users/dcramer/src/peated/apps/web/src/routes/bottles.tsx":"120","/Users/dcramer/src/peated/apps/web/src/routes/brandDetails.tsx":"121","/Users/dcramer/src/peated/apps/web/src/routes/brands.tsx":"122","/Users/dcramer/src/peated/apps/web/src/routes/distillerDetails.tsx":"123","/Users/dcramer/src/peated/apps/web/src/routes/distillers.tsx":"124","/Users/dcramer/src/peated/apps/web/src/routes/editBottle.tsx":"125","/Users/dcramer/src/peated/apps/web/src/routes/login.tsx":"126","/Users/dcramer/src/peated/apps/web/src/routes/root.tsx":"127","/Users/dcramer/src/peated/apps/web/src/routes/search.tsx":"128","/Users/dcramer/src/peated/apps/web/src/routes/settings.tsx":"129","/Users/dcramer/src/peated/apps/web/src/routes/userDetails.tsx":"130","/Users/dcramer/src/peated/apps/web/src/routes.tsx":"131","/Users/dcramer/src/peated/apps/web/src/service-worker/claims-sw.ts":"132","/Users/dcramer/src/peated/apps/web/src/service-worker/prompt-sw.ts":"133","/Users/dcramer/src/peated/apps/web/src/types.ts":"134","/Users/dcramer/src/peated/apps/web/tailwind.config.js":"135","/Users/dcramer/src/peated/apps/web/vite-env.d.ts":"136","/Users/dcramer/src/peated/apps/web/vite.config.ts":"137","/Users/dcramer/src/peated/apps/web/src/components/selectField/createOptionDialog.tsx":"138","/Users/dcramer/src/peated/apps/web/src/components/selectField/index.tsx":"139","/Users/dcramer/src/peated/apps/web/src/components/selectField/selectDialog.tsx":"140","/Users/dcramer/src/peated/apps/web/src/components/selectField/transitions.tsx":"141","/Users/dcramer/src/peated/apps/web/src/components/selectField/types.tsx":"142"},{"size":729,"mtime":1683868559156,"results":"143","hashOfConfig":"144"},{"size":1881,"mtime":1683867818045,"results":"145","hashOfConfig":"144"},{"size":457,"mtime":1683867818063,"results":"146","hashOfConfig":"144"},{"size":224,"mtime":1683867818075,"results":"147","hashOfConfig":"144"},{"size":1510,"mtime":1683867818104,"results":"148","hashOfConfig":"144"},{"size":895,"mtime":1683867818117,"results":"149","hashOfConfig":"144"},{"size":730,"mtime":1683867818136,"results":"150","hashOfConfig":"144"},{"size":2088,"mtime":1683867818158,"results":"151","hashOfConfig":"144"},{"size":6238,"mtime":1683867818201,"results":"152","hashOfConfig":"144"},{"size":702,"mtime":1683867818214,"results":"153","hashOfConfig":"144"},{"size":432,"mtime":1683867818229,"results":"154","hashOfConfig":"144"},{"size":931,"mtime":1683867818245,"results":"155","hashOfConfig":"144"},{"size":1794,"mtime":1683867818261,"results":"156","hashOfConfig":"144"},{"size":345,"mtime":1683868217646,"results":"157","hashOfConfig":"144"},{"size":671,"mtime":1683867818284,"results":"158","hashOfConfig":"144"},{"size":371,"mtime":1683867818294,"results":"159","hashOfConfig":"144"},{"size":419,"mtime":1683867818312,"results":"160","hashOfConfig":"144"},{"size":2623,"mtime":1683867818338,"results":"161","hashOfConfig":"144"},{"size":382,"mtime":1683867818351,"results":"162","hashOfConfig":"144"},{"size":863,"mtime":1683867818369,"results":"163","hashOfConfig":"144"},{"size":730,"mtime":1683867818382,"results":"164","hashOfConfig":"144"},{"size":2069,"mtime":1683867818407,"results":"165","hashOfConfig":"144"},{"size":602,"mtime":1683867818420,"results":"166","hashOfConfig":"144"},{"size":12584,"mtime":1683867818459,"results":"167","hashOfConfig":"144"},{"size":3322,"mtime":1683867818479,"results":"168","hashOfConfig":"144"},{"size":1426,"mtime":1683867818491,"results":"169","hashOfConfig":"144"},{"size":2240,"mtime":1683867818508,"results":"170","hashOfConfig":"144"},{"size":4746,"mtime":1683867818531,"results":"171","hashOfConfig":"144"},{"size":1367,"mtime":1683867818557,"results":"172","hashOfConfig":"144"},{"size":837,"mtime":1683867818572,"results":"173","hashOfConfig":"144"},{"size":3031,"mtime":1683868263239,"results":"174","hashOfConfig":"144"},{"size":1513,"mtime":1683867818607,"results":"175","hashOfConfig":"144"},{"size":642,"mtime":1683867818617,"results":"176","hashOfConfig":"144"},{"size":1895,"mtime":1683867818634,"results":"177","hashOfConfig":"144"},{"size":821,"mtime":1683867818646,"results":"178","hashOfConfig":"144"},{"size":569,"mtime":1683867818657,"results":"179","hashOfConfig":"144"},{"size":1971,"mtime":1683867818671,"results":"180","hashOfConfig":"144"},{"size":1086,"mtime":1683867818683,"results":"181","hashOfConfig":"144"},{"size":1703,"mtime":1683867818697,"results":"182","hashOfConfig":"144"},{"size":1775,"mtime":1683867818712,"results":"183","hashOfConfig":"144"},{"size":2213,"mtime":1683867818728,"results":"184","hashOfConfig":"144"},{"size":3534,"mtime":1683867818752,"results":"185","hashOfConfig":"144"},{"size":1939,"mtime":1683867818768,"results":"186","hashOfConfig":"144"},{"size":1518,"mtime":1683867818781,"results":"187","hashOfConfig":"144"},{"size":3012,"mtime":1683867818798,"results":"188","hashOfConfig":"144"},{"size":753,"mtime":1683867818809,"results":"189","hashOfConfig":"144"},{"size":1362,"mtime":1683867818823,"results":"190","hashOfConfig":"144"},{"size":1040,"mtime":1683867818834,"results":"191","hashOfConfig":"144"},{"size":4991,"mtime":1683867818853,"results":"192","hashOfConfig":"144"},{"size":1956,"mtime":1683867818869,"results":"193","hashOfConfig":"144"},{"size":1609,"mtime":1683867818882,"results":"194","hashOfConfig":"144"},{"size":1946,"mtime":1683867818897,"results":"195","hashOfConfig":"144"},{"size":1659,"mtime":1683867818912,"results":"196","hashOfConfig":"144"},{"size":1333,"mtime":1683867818925,"results":"197","hashOfConfig":"144"},{"size":1664,"mtime":1683867818943,"results":"198","hashOfConfig":"144"},{"size":374,"mtime":1683867818956,"results":"199","hashOfConfig":"144"},{"size":3673,"mtime":1683867818976,"results":"200","hashOfConfig":"144"},{"size":545,"mtime":1683867818989,"results":"201","hashOfConfig":"144"},{"size":1050,"mtime":1683867819025,"results":"202","hashOfConfig":"144"},{"size":6801,"mtime":1683875994225,"results":"203","hashOfConfig":"204"},{"size":1121,"mtime":1683867819062,"results":"205","hashOfConfig":"144"},{"size":2779,"mtime":1683867819088,"results":"206","hashOfConfig":"207"},{"size":126795,"mtime":1683867819230,"results":"208","hashOfConfig":"207"},{"size":126795,"mtime":1683867819345,"results":"209","hashOfConfig":"207"},{"size":1824683,"mtime":1683867439454,"results":"210","hashOfConfig":"211"},{"size":9077,"mtime":1683867439453,"results":"212","hashOfConfig":"211"},{"size":1906,"mtime":1683866626641,"results":"213","hashOfConfig":"211"},{"size":23674,"mtime":1683867439453,"results":"214","hashOfConfig":"211"},{"size":109,"mtime":1683867819375,"results":"215","hashOfConfig":"144"},{"size":470,"mtime":1683867819392,"results":"216","hashOfConfig":"144"},{"size":4308,"mtime":1683867819436,"results":"217","hashOfConfig":"144"},{"size":1871,"mtime":1683867819453,"results":"218","hashOfConfig":"144"},{"size":163,"mtime":1683867819480,"results":"219","hashOfConfig":"144"},{"size":3864,"mtime":1683867819498,"results":"220","hashOfConfig":"144"},{"size":1593,"mtime":1683874842005,"results":"221","hashOfConfig":"204"},{"size":2770,"mtime":1683867819526,"results":"222","hashOfConfig":"144"},{"size":2206,"mtime":1683869943237,"results":"223","hashOfConfig":"204"},{"size":972,"mtime":1683867819556,"results":"224","hashOfConfig":"144"},{"size":5235,"mtime":1683874841913,"results":"225","hashOfConfig":"204"},{"size":1540,"mtime":1683874841998,"results":"226","hashOfConfig":"204"},{"size":2814,"mtime":1683867819604,"results":"227","hashOfConfig":"144"},{"size":262,"mtime":1683867819615,"results":"228","hashOfConfig":"144"},{"size":496,"mtime":1683867819626,"results":"229","hashOfConfig":"144"},{"size":503,"mtime":1683868296355,"results":"230","hashOfConfig":"144"},{"size":1315,"mtime":1683872482194,"results":"231","hashOfConfig":"204"},{"size":1609,"mtime":1683867819663,"results":"232","hashOfConfig":"144"},{"size":433,"mtime":1683867819673,"results":"233","hashOfConfig":"144"},{"size":607,"mtime":1683867819684,"results":"234","hashOfConfig":"144"},{"size":176,"mtime":1683867819695,"results":"235","hashOfConfig":"144"},{"size":4083,"mtime":1683872444651,"results":"236","hashOfConfig":"204"},{"size":2051,"mtime":1683867819726,"results":"237","hashOfConfig":"144"},{"size":675,"mtime":1683867819737,"results":"238","hashOfConfig":"144"},{"size":3131,"mtime":1683872107786,"results":"239","hashOfConfig":"204"},{"size":629,"mtime":1683867819766,"results":"240","hashOfConfig":"144"},{"size":1756,"mtime":1683868566527,"results":"241","hashOfConfig":"144"},{"size":286,"mtime":1683867819827,"results":"242","hashOfConfig":"144"},{"size":312,"mtime":1683867819835,"results":"243","hashOfConfig":"144"},{"size":2255,"mtime":1683867819851,"results":"244","hashOfConfig":"144"},{"size":1411,"mtime":1683867819887,"results":"245","hashOfConfig":"144"},{"size":3335,"mtime":1683874894414,"results":"246","hashOfConfig":"204"},{"size":3175,"mtime":1683868034101,"results":"247","hashOfConfig":"144"},{"size":363,"mtime":1683872015092,"results":"248","hashOfConfig":"204"},{"size":637,"mtime":1683867819937,"results":"249","hashOfConfig":"144"},{"size":641,"mtime":1683867819947,"results":"250","hashOfConfig":"144"},{"size":980,"mtime":1683868049029,"results":"251","hashOfConfig":"144"},{"size":707,"mtime":1683867819967,"results":"252","hashOfConfig":"144"},{"size":426,"mtime":1683867819977,"results":"253","hashOfConfig":"144"},{"size":2646,"mtime":1683868510912,"results":"254","hashOfConfig":"144"},{"size":2586,"mtime":1683867884908,"results":"255","hashOfConfig":"144"},{"size":1417,"mtime":1683867820015,"results":"256","hashOfConfig":"144"},{"size":942,"mtime":1683867820027,"results":"257","hashOfConfig":"144"},{"size":3551,"mtime":1683867959905,"results":"258","hashOfConfig":"144"},{"size":140,"mtime":1683867820051,"results":"259","hashOfConfig":"144"},{"size":443,"mtime":1683867820062,"results":"260","hashOfConfig":"144"},{"size":2656,"mtime":1683867801304,"results":"261","hashOfConfig":"144"},{"size":1785,"mtime":1683867820107,"results":"262","hashOfConfig":"144"},{"size":5023,"mtime":1683874794456,"results":"263","hashOfConfig":"204"},{"size":4636,"mtime":1683867820146,"results":"264","hashOfConfig":"144"},{"size":4778,"mtime":1683867820166,"results":"265","hashOfConfig":"144"},{"size":1515,"mtime":1683867820180,"results":"266","hashOfConfig":"144"},{"size":2113,"mtime":1683867820195,"results":"267","hashOfConfig":"144"},{"size":1524,"mtime":1683867820208,"results":"268","hashOfConfig":"144"},{"size":2412,"mtime":1683867922335,"results":"269","hashOfConfig":"144"},{"size":1580,"mtime":1683867820234,"results":"270","hashOfConfig":"144"},{"size":5229,"mtime":1683874842014,"results":"271","hashOfConfig":"204"},{"size":4994,"mtime":1683867863440,"results":"272","hashOfConfig":"144"},{"size":755,"mtime":1683867820282,"results":"273","hashOfConfig":"144"},{"size":5752,"mtime":1683867820306,"results":"274","hashOfConfig":"144"},{"size":3072,"mtime":1683867820326,"results":"275","hashOfConfig":"144"},{"size":3800,"mtime":1683867820342,"results":"276","hashOfConfig":"144"},{"size":2919,"mtime":1683867820092,"results":"277","hashOfConfig":"144"},{"size":643,"mtime":1683867820358,"results":"278","hashOfConfig":"144"},{"size":583,"mtime":1683867820368,"results":"279","hashOfConfig":"144"},{"size":1387,"mtime":1683867820401,"results":"280","hashOfConfig":"144"},{"size":1301,"mtime":1683866914185,"results":"281","hashOfConfig":"282"},{"size":505,"mtime":1683867820426,"results":"283","hashOfConfig":"144"},{"size":3913,"mtime":1683867820441,"results":"284","hashOfConfig":"144"},{"size":2286,"mtime":1683870695641,"results":"285","hashOfConfig":"204"},{"size":4704,"mtime":1683874823048,"results":"286","hashOfConfig":"204"},{"size":7723,"mtime":1683873312277,"results":"287","hashOfConfig":"204"},{"size":971,"mtime":1683874101380,"results":"288","hashOfConfig":"204"},{"size":270,"mtime":1683870643482,"results":"289","hashOfConfig":"204"},{"filePath":"290","messages":"291","suppressedMessages":"292","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"1vs59bq",{"filePath":"293","messages":"294","suppressedMessages":"295","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"296","messages":"297","suppressedMessages":"298","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"299","messages":"300","suppressedMessages":"301","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"302","messages":"303","suppressedMessages":"304","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"305","messages":"306","suppressedMessages":"307","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"308","messages":"309","suppressedMessages":"310","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"311","messages":"312","suppressedMessages":"313","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"314","messages":"315","suppressedMessages":"316","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"317","messages":"318","suppressedMessages":"319","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"320","messages":"321","suppressedMessages":"322","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"323","messages":"324","suppressedMessages":"325","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"326","messages":"327","suppressedMessages":"328","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"329","messages":"330","suppressedMessages":"331","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"332","messages":"333","suppressedMessages":"334","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"335","messages":"336","suppressedMessages":"337","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"338","messages":"339","suppressedMessages":"340","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"341","messages":"342","suppressedMessages":"343","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"344","messages":"345","suppressedMessages":"346","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"347","messages":"348","suppressedMessages":"349","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"350","messages":"351","suppressedMessages":"352","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"353","messages":"354","suppressedMessages":"355","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"356","messages":"357","suppressedMessages":"358","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"359","messages":"360","suppressedMessages":"361","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"362","messages":"363","suppressedMessages":"364","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"365","messages":"366","suppressedMessages":"367","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"368","messages":"369","suppressedMessages":"370","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"371","messages":"372","suppressedMessages":"373","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"374","messages":"375","suppressedMessages":"376","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"377","messages":"378","suppressedMessages":"379","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"380","messages":"381","suppressedMessages":"382","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"383","messages":"384","suppressedMessages":"385","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"386","messages":"387","suppressedMessages":"388","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"389","messages":"390","suppressedMessages":"391","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"392","messages":"393","suppressedMessages":"394","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"395","messages":"396","suppressedMessages":"397","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"398","messages":"399","suppressedMessages":"400","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"401","messages":"402","suppressedMessages":"403","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"404","messages":"405","suppressedMessages":"406","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"407","messages":"408","suppressedMessages":"409","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"410","messages":"411","suppressedMessages":"412","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"413","messages":"414","suppressedMessages":"415","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"416","messages":"417","suppressedMessages":"418","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"419","messages":"420","suppressedMessages":"421","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"422","messages":"423","suppressedMessages":"424","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"425","messages":"426","suppressedMessages":"427","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"428","messages":"429","suppressedMessages":"430","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"431","messages":"432","suppressedMessages":"433","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"434","messages":"435","suppressedMessages":"436","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"437","messages":"438","suppressedMessages":"439","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"440","messages":"441","suppressedMessages":"442","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"443","messages":"444","suppressedMessages":"445","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"446","messages":"447","suppressedMessages":"448","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"449","messages":"450","suppressedMessages":"451","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"452","messages":"453","suppressedMessages":"454","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"455","messages":"456","suppressedMessages":"457","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"458","messages":"459","suppressedMessages":"460","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"461","messages":"462","suppressedMessages":"463","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"464","messages":"465","suppressedMessages":"466","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"467","messages":"468","suppressedMessages":"469","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"1psbues",{"filePath":"470","messages":"471","suppressedMessages":"472","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"473","messages":"474","suppressedMessages":"475","errorCount":2,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},"g4ju7h",{"filePath":"476","messages":"477","suppressedMessages":"478","errorCount":18,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"479","messages":"480","suppressedMessages":"481","errorCount":18,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"482","messages":"483","suppressedMessages":"484","errorCount":646,"fatalErrorCount":0,"warningCount":94,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},"1yc5r2n",{"filePath":"485","messages":"486","suppressedMessages":"487","errorCount":9,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"488","messages":"489","suppressedMessages":"490","errorCount":2,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"491","messages":"492","suppressedMessages":"493","errorCount":14,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"494","messages":"495","suppressedMessages":"496","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"497","messages":"498","suppressedMessages":"499","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"500","messages":"501","suppressedMessages":"502","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"503","messages":"504","suppressedMessages":"505","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"506","messages":"507","suppressedMessages":"508","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"509","messages":"510","suppressedMessages":"511","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"512","messages":"513","suppressedMessages":"514","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"515","messages":"516","suppressedMessages":"517","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"518","messages":"519","suppressedMessages":"520","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"521","messages":"522","suppressedMessages":"523","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"524","messages":"525","suppressedMessages":"526","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"527","messages":"528","suppressedMessages":"529","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"530","messages":"531","suppressedMessages":"532","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"533","messages":"534","suppressedMessages":"535","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"536","messages":"537","suppressedMessages":"538","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"539","messages":"540","suppressedMessages":"541","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"542","messages":"543","suppressedMessages":"544","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"545","messages":"546","suppressedMessages":"547","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"548","messages":"549","suppressedMessages":"550","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"551","messages":"552","suppressedMessages":"553","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"554","messages":"555","suppressedMessages":"556","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"557","messages":"558","suppressedMessages":"559","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"560","messages":"561","suppressedMessages":"562","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"563","messages":"564","suppressedMessages":"565","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"566","messages":"567","suppressedMessages":"568","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"569","messages":"570","suppressedMessages":"571","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"572","messages":"573","suppressedMessages":"574","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"575","messages":"576","suppressedMessages":"577","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"578","messages":"579","suppressedMessages":"580","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"581","messages":"582","suppressedMessages":"583","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"584","messages":"585","suppressedMessages":"586","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"587","messages":"588","suppressedMessages":"589","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"590","messages":"591","suppressedMessages":"592","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"593","messages":"594","suppressedMessages":"595","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"596","messages":"597","suppressedMessages":"598","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"599","messages":"600","suppressedMessages":"601","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"602","messages":"603","suppressedMessages":"604","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"605","messages":"606","suppressedMessages":"607","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"608","messages":"609","suppressedMessages":"610","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"611","messages":"612","suppressedMessages":"613","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"614","messages":"615","suppressedMessages":"616","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"617","messages":"618","suppressedMessages":"619","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"620","messages":"621","suppressedMessages":"622","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"623","messages":"624","suppressedMessages":"625","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"626","messages":"627","suppressedMessages":"628","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"629","messages":"630","suppressedMessages":"631","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"632","messages":"633","suppressedMessages":"634","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"635","messages":"636","suppressedMessages":"637","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"638","messages":"639","suppressedMessages":"640","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"641","messages":"642","suppressedMessages":"643","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"644","messages":"645","suppressedMessages":"646","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"647","messages":"648","suppressedMessages":"649","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"650","messages":"651","suppressedMessages":"652","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"653","messages":"654","suppressedMessages":"655","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"656","messages":"657","suppressedMessages":"658","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"659","messages":"660","suppressedMessages":"661","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"662","messages":"663","suppressedMessages":"664","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"665","messages":"666","suppressedMessages":"667","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"668","messages":"669","suppressedMessages":"670","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"671","messages":"672","suppressedMessages":"673","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"674","messages":"675","suppressedMessages":"676","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"677","messages":"678","suppressedMessages":"679","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"680","messages":"681","suppressedMessages":"682","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"683","messages":"684","suppressedMessages":"685","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"686","messages":"687","suppressedMessages":"688","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"689","messages":"690","suppressedMessages":"691","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"692","messages":"693","suppressedMessages":"694","errorCount":2,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},"pnm92l",{"filePath":"695","messages":"696","suppressedMessages":"697","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"698","messages":"699","suppressedMessages":"700","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"701","messages":"702","suppressedMessages":"703","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"704","messages":"705","suppressedMessages":"706","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"707","messages":"708","suppressedMessages":"709","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"710","messages":"711","suppressedMessages":"712","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"713","messages":"714","suppressedMessages":"715","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"/Users/dcramer/src/peated/.eslintrc.js",[],[],"/Users/dcramer/src/peated/apps/api/src/app.ts",[],[],"/Users/dcramer/src/peated/apps/api/src/bin/db.ts",[],[],"/Users/dcramer/src/peated/apps/api/src/bin/load-mocks.ts",[],[],"/Users/dcramer/src/peated/apps/api/src/bin/user.ts",[],[],"/Users/dcramer/src/peated/apps/api/src/config.ts",[],[],"/Users/dcramer/src/peated/apps/api/src/db/index.ts",[],[],"/Users/dcramer/src/peated/apps/api/src/db/migrate.ts",[],[],"/Users/dcramer/src/peated/apps/api/src/db/schema.ts",[],[],"/Users/dcramer/src/peated/apps/api/src/globals.d.ts",[],[],"/Users/dcramer/src/peated/apps/api/src/instruments.ts",[],[],"/Users/dcramer/src/peated/apps/api/src/lib/auth.ts",[],[],"/Users/dcramer/src/peated/apps/api/src/lib/db.ts",[],[],"/Users/dcramer/src/peated/apps/api/src/lib/filter.ts",[],[],"/Users/dcramer/src/peated/apps/api/src/lib/paging.test.ts",[],[],"/Users/dcramer/src/peated/apps/api/src/lib/paging.ts",[],[],"/Users/dcramer/src/peated/apps/api/src/lib/test/expects.ts",[],[],"/Users/dcramer/src/peated/apps/api/src/lib/test/fixtures.ts",[],[],"/Users/dcramer/src/peated/apps/api/src/lib/transformers/bottle.ts",[],[],"/Users/dcramer/src/peated/apps/api/src/lib/transformers/tasting.ts",[],[],"/Users/dcramer/src/peated/apps/api/src/lib/transformers/user.ts",[],[],"/Users/dcramer/src/peated/apps/api/src/lib/uploads.ts",[],[],"/Users/dcramer/src/peated/apps/api/src/middleware/auth.ts",[],[],"/Users/dcramer/src/peated/apps/api/src/routes/addBottle.test.ts",[],[],"/Users/dcramer/src/peated/apps/api/src/routes/addBottle.ts",[],[],"/Users/dcramer/src/peated/apps/api/src/routes/addEntity.ts",[],[],"/Users/dcramer/src/peated/apps/api/src/routes/addTasting.test.ts",[],[],"/Users/dcramer/src/peated/apps/api/src/routes/addTasting.ts",[],[],"/Users/dcramer/src/peated/apps/api/src/routes/authBasic.ts",[],[],"/Users/dcramer/src/peated/apps/api/src/routes/authDetails.ts",[],[],"/Users/dcramer/src/peated/apps/api/src/routes/authGoogle.ts",[],[],"/Users/dcramer/src/peated/apps/api/src/routes/entities.test.ts",[],[],"/Users/dcramer/src/peated/apps/api/src/routes/getBottle.test.ts",[],[],"/Users/dcramer/src/peated/apps/api/src/routes/getBottle.tsx",[],[],"/Users/dcramer/src/peated/apps/api/src/routes/getEntity.ts",[],[],"/Users/dcramer/src/peated/apps/api/src/routes/getTasting.test.ts",[],[],"/Users/dcramer/src/peated/apps/api/src/routes/getTasting.ts",[],[],"/Users/dcramer/src/peated/apps/api/src/routes/getUser.test.ts",[],[],"/Users/dcramer/src/peated/apps/api/src/routes/getUser.ts",[],[],"/Users/dcramer/src/peated/apps/api/src/routes/index.ts",[],[],"/Users/dcramer/src/peated/apps/api/src/routes/listBottles.test.ts",[],[],"/Users/dcramer/src/peated/apps/api/src/routes/listBottles.ts",[],[],"/Users/dcramer/src/peated/apps/api/src/routes/listEntities.ts",[],[],"/Users/dcramer/src/peated/apps/api/src/routes/listTastings.test.ts",[],[],"/Users/dcramer/src/peated/apps/api/src/routes/listTastings.ts",[],[],"/Users/dcramer/src/peated/apps/api/src/routes/listUsers.test.ts",[],[],"/Users/dcramer/src/peated/apps/api/src/routes/listUsers.ts",[],[],"/Users/dcramer/src/peated/apps/api/src/routes/updateBottle.test.ts",[],[],"/Users/dcramer/src/peated/apps/api/src/routes/updateBottle.ts",[],[],"/Users/dcramer/src/peated/apps/api/src/routes/updateTastingImage.ts",[],[],"/Users/dcramer/src/peated/apps/api/src/routes/updateUser.ts",[],[],"/Users/dcramer/src/peated/apps/api/src/routes/updateUserAvatar.ts",[],[],"/Users/dcramer/src/peated/apps/api/src/routes/uploads.ts",[],[],"/Users/dcramer/src/peated/apps/api/src/schemas/bottle.tsx",[],[],"/Users/dcramer/src/peated/apps/api/src/sentryPlugin.ts",[],[],"/Users/dcramer/src/peated/apps/api/src/server.ts",[],[],"/Users/dcramer/src/peated/apps/api/src/test/setup-test-env.ts",[],[],"/Users/dcramer/src/peated/apps/api/vitest.config.ts",[],[],"/Users/dcramer/src/peated/apps/scraper/src/api.ts",[],[],"/Users/dcramer/src/peated/apps/scraper/src/main.ts",[],[],"/Users/dcramer/src/peated/apps/scraper/src/scraper.ts",[],[],"/Users/dcramer/src/peated/apps/web/dev-dist/sw.js",["716","717"],[],"/Users/dcramer/src/peated/apps/web/dev-dist/workbox-6966ae98.js",["718","719","720","721","722","723","724","725","726","727","728","729","730","731","732","733","734","735"],[],"/Users/dcramer/src/peated/apps/web/dev-dist/workbox-b4947dc9.js",["736","737","738","739","740","741","742","743","744","745","746","747","748","749","750","751","752","753"],[],"/Users/dcramer/src/peated/apps/web/dist/assets/index.js",["754","755","756","757","758","759","760","761","762","763","764","765","766","767","768","769","770","771","772","773","774","775","776","777","778","779","780","781","782","783","784","785","786","787","788","789","790","791","792","793","794","795","796","797","798","799","800","801","802","803","804","805","806","807","808","809","810","811","812","813","814","815","816","817","818","819","820","821","822","823","824","825","826","827","828","829","830","831","832","833","834","835","836","837","838","839","840","841","842","843","844","845","846","847","848","849","850","851","852","853","854","855","856","857","858","859","860","861","862","863","864","865","866","867","868","869","870","871","872","873","874","875","876","877","878","879","880","881","882","883","884","885","886","887","888","889","890","891","892","893","894","895","896","897","898","899","900","901","902","903","904","905","906","907","908","909","910","911","912","913","914","915","916","917","918","919","920","921","922","923","924","925","926","927","928","929","930","931","932","933","934","935","936","937","938","939","940","941","942","943","944","945","946","947","948","949","950","951","952","953","954","955","956","957","958","959","960","961","962","963","964","965","966","967","968","969","970","971","972","973","974","975","976","977","978","979","980","981","982","983","984","985","986","987","988","989","990","991","992","993","994","995","996","997","998","999","1000","1001","1002","1003","1004","1005","1006","1007","1008","1009","1010","1011","1012","1013","1014","1015","1016","1017","1018","1019","1020","1021","1022","1023","1024","1025","1026","1027","1028","1029","1030","1031","1032","1033","1034","1035","1036","1037","1038","1039","1040","1041","1042","1043","1044","1045","1046","1047","1048","1049","1050","1051","1052","1053","1054","1055","1056","1057","1058","1059","1060","1061","1062","1063","1064","1065","1066","1067","1068","1069","1070","1071","1072","1073","1074","1075","1076","1077","1078","1079","1080","1081","1082","1083","1084","1085","1086","1087","1088","1089","1090","1091","1092","1093","1094","1095","1096","1097","1098","1099","1100","1101","1102","1103","1104","1105","1106","1107","1108","1109","1110","1111","1112","1113","1114","1115","1116","1117","1118","1119","1120","1121","1122","1123","1124","1125","1126","1127","1128","1129","1130","1131","1132","1133","1134","1135","1136","1137","1138","1139","1140","1141","1142","1143","1144","1145","1146","1147","1148","1149","1150","1151","1152","1153","1154","1155","1156","1157","1158","1159","1160","1161","1162","1163","1164","1165","1166","1167","1168","1169","1170","1171","1172","1173","1174","1175","1176","1177","1178","1179","1180","1181","1182","1183","1184","1185","1186","1187","1188","1189","1190","1191","1192","1193","1194","1195","1196","1197","1198","1199","1200","1201","1202","1203","1204","1205","1206","1207","1208","1209","1210","1211","1212","1213","1214","1215","1216","1217","1218","1219","1220","1221","1222","1223","1224","1225","1226","1227","1228","1229","1230","1231","1232","1233","1234","1235","1236","1237","1238","1239","1240","1241","1242","1243","1244","1245","1246","1247","1248","1249","1250","1251","1252","1253","1254","1255","1256","1257","1258","1259","1260","1261","1262","1263","1264","1265","1266","1267","1268","1269","1270","1271","1272","1273","1274","1275","1276","1277","1278","1279","1280","1281","1282","1283","1284","1285","1286","1287","1288","1289","1290","1291","1292","1293","1294","1295","1296","1297","1298","1299","1300","1301","1302","1303","1304","1305","1306","1307","1308","1309","1310","1311","1312","1313","1314","1315","1316","1317","1318","1319","1320","1321","1322","1323","1324","1325","1326","1327","1328","1329","1330","1331","1332","1333","1334","1335","1336","1337","1338","1339","1340","1341","1342","1343","1344","1345","1346","1347","1348","1349","1350","1351","1352","1353","1354","1355","1356","1357","1358","1359","1360","1361","1362","1363","1364","1365","1366","1367","1368","1369","1370","1371","1372","1373","1374","1375","1376","1377","1378","1379","1380","1381","1382","1383","1384","1385","1386","1387","1388","1389","1390","1391","1392","1393","1394","1395","1396","1397","1398","1399","1400","1401","1402","1403","1404","1405","1406","1407","1408","1409","1410","1411","1412","1413","1414","1415","1416","1417","1418","1419","1420","1421","1422","1423","1424","1425","1426","1427","1428","1429","1430","1431","1432","1433","1434","1435","1436","1437","1438","1439","1440","1441","1442","1443","1444","1445","1446","1447","1448","1449","1450","1451","1452","1453","1454","1455","1456","1457","1458","1459","1460","1461","1462","1463","1464","1465","1466","1467","1468","1469","1470","1471","1472","1473","1474","1475","1476","1477","1478","1479","1480","1481","1482","1483","1484","1485","1486","1487","1488","1489","1490","1491","1492","1493"],[],"/Users/dcramer/src/peated/apps/web/dist/assets/workbox-window.prod.es5.js",["1494","1495","1496","1497","1498","1499","1500","1501","1502"],[],"/Users/dcramer/src/peated/apps/web/dist/sw.js",["1503","1504"],[],"/Users/dcramer/src/peated/apps/web/dist/workbox-d2983725.js",["1505","1506","1507","1508","1509","1510","1511","1512","1513","1514","1515","1516","1517","1518","1519"],[],"/Users/dcramer/src/peated/apps/web/postcss.config.js",[],[],"/Users/dcramer/src/peated/apps/web/src/components/alert.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/components/appHeader.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/components/bottleCard.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/components/bottleName.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/components/bottleTable.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/components/brandField.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/components/brandTable.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/components/button.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/components/chip.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/components/countryField.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/components/distillerField.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/components/distillerTable.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/components/fieldset.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/components/floatingButton.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/components/formError.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/components/formField.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/components/formHeader.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/components/formLabel.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/components/header.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/components/helpText.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/components/imageField.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/components/layout.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/components/listItem.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/components/rating.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/components/ratingField.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/components/reloadPrompt.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/components/screen.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/components/scrollView.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/components/searchHeader.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/components/spinner.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/components/tagsField.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/components/tastingListItem.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/components/textArea.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/components/textAreaField.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/components/textField.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/components/textInput.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/components/userAvatar.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/config.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/error-page.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/hooks/useAuth.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/hooks/useLocalStorage.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/hooks/useOnlineStatus.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/lib/api.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/lib/classNames.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/lib/strings.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/main.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/routes/activity.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/routes/addBottle.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/routes/addTasting.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/routes/bottleDetails.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/routes/bottles.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/routes/brandDetails.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/routes/brands.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/routes/distillerDetails.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/routes/distillers.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/routes/editBottle.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/routes/login.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/routes/root.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/routes/search.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/routes/settings.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/routes/userDetails.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/routes.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/service-worker/claims-sw.ts",[],[],"/Users/dcramer/src/peated/apps/web/src/service-worker/prompt-sw.ts",[],[],"/Users/dcramer/src/peated/apps/web/src/types.ts",[],[],"/Users/dcramer/src/peated/apps/web/tailwind.config.js",["1520","1521","1522"],[],"/Users/dcramer/src/peated/apps/web/vite-env.d.ts",[],[],"/Users/dcramer/src/peated/apps/web/vite.config.ts",[],[],"/Users/dcramer/src/peated/apps/web/src/components/selectField/createOptionDialog.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/components/selectField/index.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/components/selectField/selectDialog.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/components/selectField/transitions.tsx",[],[],"/Users/dcramer/src/peated/apps/web/src/components/selectField/types.tsx",[],[],{"ruleId":"1523","severity":2,"message":"1524","line":34,"column":11,"nodeType":"1525","messageId":"1526","endLine":34,"endColumn":24},{"ruleId":"1523","severity":2,"message":"1527","line":71,"column":1,"nodeType":"1525","messageId":"1526","endLine":71,"endColumn":7},{"ruleId":"1523","severity":2,"message":"1527","line":1,"column":1,"nodeType":"1525","messageId":"1526","endLine":1,"endColumn":7},{"ruleId":"1528","severity":2,"message":"1529","line":4,"column":3,"nodeType":"1530","messageId":"1531","endLine":4,"endColumn":16},{"ruleId":"1523","severity":2,"message":"1532","line":6,"column":35,"nodeType":"1525","messageId":"1526","endLine":6,"endColumn":36},{"ruleId":"1533","severity":2,"message":"1534","line":7,"column":15,"nodeType":"1535","messageId":"1536","endLine":7,"endColumn":17,"suggestions":"1537"},{"ruleId":"1528","severity":2,"message":"1529","line":554,"column":3,"nodeType":"1530","messageId":"1531","endLine":554,"endColumn":16},{"ruleId":"1523","severity":2,"message":"1532","line":556,"column":38,"nodeType":"1525","messageId":"1526","endLine":556,"endColumn":39},{"ruleId":"1533","severity":2,"message":"1534","line":557,"column":15,"nodeType":"1535","messageId":"1536","endLine":557,"endColumn":17,"suggestions":"1538"},{"ruleId":"1523","severity":2,"message":"1539","line":1325,"column":51,"nodeType":"1525","messageId":"1526","endLine":1325,"endColumn":63},{"ruleId":"1528","severity":2,"message":"1529","line":1385,"column":3,"nodeType":"1530","messageId":"1531","endLine":1385,"endColumn":16},{"ruleId":"1523","severity":2,"message":"1532","line":1387,"column":41,"nodeType":"1525","messageId":"1526","endLine":1387,"endColumn":42},{"ruleId":"1533","severity":2,"message":"1534","line":1388,"column":15,"nodeType":"1535","messageId":"1536","endLine":1388,"endColumn":17,"suggestions":"1540"},{"ruleId":"1528","severity":2,"message":"1529","line":1849,"column":3,"nodeType":"1530","messageId":"1531","endLine":1849,"endColumn":16},{"ruleId":"1523","severity":2,"message":"1532","line":1851,"column":41,"nodeType":"1525","messageId":"1526","endLine":1851,"endColumn":42},{"ruleId":"1533","severity":2,"message":"1534","line":1852,"column":15,"nodeType":"1535","messageId":"1536","endLine":1852,"endColumn":17,"suggestions":"1541"},{"ruleId":"1523","severity":2,"message":"1542","line":1930,"column":54,"nodeType":"1525","messageId":"1526","endLine":1930,"endColumn":69},{"ruleId":"1523","severity":2,"message":"1543","line":1969,"column":26,"nodeType":"1525","messageId":"1526","endLine":1969,"endColumn":36},{"ruleId":"1544","severity":2,"message":"1545","line":2014,"column":13,"nodeType":"1546","messageId":"1536","endLine":2014,"endColumn":43},{"ruleId":"1523","severity":2,"message":"1543","line":2517,"column":30,"nodeType":"1525","messageId":"1526","endLine":2517,"endColumn":40},{"ruleId":"1523","severity":2,"message":"1527","line":1,"column":1,"nodeType":"1525","messageId":"1526","endLine":1,"endColumn":7},{"ruleId":"1528","severity":2,"message":"1529","line":4,"column":3,"nodeType":"1530","messageId":"1531","endLine":4,"endColumn":16},{"ruleId":"1523","severity":2,"message":"1532","line":6,"column":35,"nodeType":"1525","messageId":"1526","endLine":6,"endColumn":36},{"ruleId":"1533","severity":2,"message":"1534","line":7,"column":15,"nodeType":"1535","messageId":"1536","endLine":7,"endColumn":17,"suggestions":"1547"},{"ruleId":"1528","severity":2,"message":"1529","line":554,"column":3,"nodeType":"1530","messageId":"1531","endLine":554,"endColumn":16},{"ruleId":"1523","severity":2,"message":"1532","line":556,"column":38,"nodeType":"1525","messageId":"1526","endLine":556,"endColumn":39},{"ruleId":"1533","severity":2,"message":"1534","line":557,"column":15,"nodeType":"1535","messageId":"1536","endLine":557,"endColumn":17,"suggestions":"1548"},{"ruleId":"1523","severity":2,"message":"1539","line":1325,"column":51,"nodeType":"1525","messageId":"1526","endLine":1325,"endColumn":63},{"ruleId":"1528","severity":2,"message":"1529","line":1385,"column":3,"nodeType":"1530","messageId":"1531","endLine":1385,"endColumn":16},{"ruleId":"1523","severity":2,"message":"1532","line":1387,"column":41,"nodeType":"1525","messageId":"1526","endLine":1387,"endColumn":42},{"ruleId":"1533","severity":2,"message":"1534","line":1388,"column":15,"nodeType":"1535","messageId":"1536","endLine":1388,"endColumn":17,"suggestions":"1549"},{"ruleId":"1528","severity":2,"message":"1529","line":1849,"column":3,"nodeType":"1530","messageId":"1531","endLine":1849,"endColumn":16},{"ruleId":"1523","severity":2,"message":"1532","line":1851,"column":41,"nodeType":"1525","messageId":"1526","endLine":1851,"endColumn":42},{"ruleId":"1533","severity":2,"message":"1534","line":1852,"column":15,"nodeType":"1535","messageId":"1536","endLine":1852,"endColumn":17,"suggestions":"1550"},{"ruleId":"1523","severity":2,"message":"1542","line":1930,"column":54,"nodeType":"1525","messageId":"1526","endLine":1930,"endColumn":69},{"ruleId":"1523","severity":2,"message":"1543","line":1969,"column":26,"nodeType":"1525","messageId":"1526","endLine":1969,"endColumn":36},{"ruleId":"1544","severity":2,"message":"1545","line":2014,"column":13,"nodeType":"1546","messageId":"1536","endLine":2014,"endColumn":43},{"ruleId":"1523","severity":2,"message":"1543","line":2517,"column":30,"nodeType":"1525","messageId":"1526","endLine":2517,"endColumn":40},{"ruleId":"1551","severity":2,"message":"1552","line":100,"column":39,"nodeType":"1553","messageId":"1536","endLine":100,"endColumn":41},{"ruleId":"1551","severity":2,"message":"1554","line":101,"column":40,"nodeType":"1553","messageId":"1536","endLine":101,"endColumn":42},{"ruleId":"1551","severity":2,"message":"1555","line":102,"column":36,"nodeType":"1553","messageId":"1536","endLine":102,"endColumn":38},{"ruleId":"1551","severity":2,"message":"1556","line":123,"column":17,"nodeType":"1557","messageId":"1536","endLine":123,"endColumn":19},{"ruleId":"1558","severity":2,"message":"1559","line":148,"column":30,"nodeType":"1560","messageId":"1561","endLine":148,"endColumn":44},{"ruleId":"1558","severity":2,"message":"1559","line":357,"column":15,"nodeType":"1560","messageId":"1561","endLine":357,"endColumn":29},{"ruleId":"1551","severity":2,"message":"1562","line":421,"column":34,"nodeType":"1553","messageId":"1536","endLine":421,"endColumn":36},{"ruleId":"1558","severity":2,"message":"1559","line":486,"column":39,"nodeType":"1560","messageId":"1561","endLine":486,"endColumn":53},{"ruleId":"1551","severity":2,"message":"1562","line":718,"column":48,"nodeType":"1553","messageId":"1536","endLine":718,"endColumn":50},{"ruleId":"1551","severity":2,"message":"1562","line":719,"column":46,"nodeType":"1553","messageId":"1536","endLine":719,"endColumn":48},{"ruleId":"1563","severity":2,"message":"1564","line":839,"column":7,"nodeType":"1565","messageId":"1566","endLine":839,"endColumn":356},{"ruleId":"1567","severity":2,"message":"1568","line":938,"column":14,"nodeType":"1565","messageId":"1569","endLine":938,"endColumn":15,"suggestions":"1570"},{"ruleId":"1558","severity":2,"message":"1559","line":974,"column":16,"nodeType":"1560","messageId":"1561","endLine":974,"endColumn":30},{"ruleId":"1571","severity":2,"message":"1572","line":1109,"column":13,"nodeType":"1573","messageId":"1574","endLine":1109,"endColumn":49},{"ruleId":"1533","severity":2,"message":"1534","line":1174,"column":19,"nodeType":"1535","messageId":"1536","endLine":1174,"endColumn":21,"suggestions":"1575"},{"ruleId":"1558","severity":2,"message":"1559","line":1258,"column":10,"nodeType":"1560","messageId":"1561","endLine":1258,"endColumn":24},{"ruleId":"1558","severity":2,"message":"1559","line":1353,"column":7,"nodeType":"1560","messageId":"1561","endLine":1353,"endColumn":21},{"ruleId":"1558","severity":2,"message":"1559","line":1355,"column":11,"nodeType":"1560","messageId":"1561","endLine":1355,"endColumn":25},{"ruleId":"1558","severity":2,"message":"1559","line":1361,"column":11,"nodeType":"1560","messageId":"1561","endLine":1361,"endColumn":25},{"ruleId":"1558","severity":2,"message":"1559","line":1361,"column":40,"nodeType":"1560","messageId":"1561","endLine":1361,"endColumn":54},{"ruleId":"1558","severity":2,"message":"1559","line":1391,"column":16,"nodeType":"1560","messageId":"1561","endLine":1391,"endColumn":30},{"ruleId":"1523","severity":2,"message":"1576","line":1463,"column":36,"nodeType":"1525","messageId":"1526","endLine":1463,"endColumn":41},{"ruleId":"1523","severity":2,"message":"1576","line":1465,"column":13,"nodeType":"1525","messageId":"1526","endLine":1465,"endColumn":18},{"ruleId":"1558","severity":2,"message":"1559","line":1549,"column":53,"nodeType":"1560","messageId":"1561","endLine":1549,"endColumn":67},{"ruleId":"1558","severity":2,"message":"1559","line":1556,"column":13,"nodeType":"1560","messageId":"1561","endLine":1556,"endColumn":27},{"ruleId":"1551","severity":2,"message":"1577","line":1644,"column":17,"nodeType":"1557","messageId":"1536","endLine":1644,"endColumn":19},{"ruleId":"1578","severity":2,"message":"1579","line":1695,"column":9,"nodeType":"1553","messageId":"1580","endLine":1695,"endColumn":23},{"ruleId":"1581","severity":1,"message":"1582","line":1704,"column":24,"nodeType":"1525","messageId":"1583","endLine":1704,"endColumn":25},{"ruleId":"1581","severity":1,"message":"1584","line":1704,"column":27,"nodeType":"1525","messageId":"1583","endLine":1704,"endColumn":28},{"ruleId":"1581","severity":1,"message":"1585","line":1704,"column":30,"nodeType":"1525","messageId":"1583","endLine":1704,"endColumn":31},{"ruleId":"1581","severity":1,"message":"1586","line":1704,"column":33,"nodeType":"1525","messageId":"1583","endLine":1704,"endColumn":34},{"ruleId":"1581","severity":1,"message":"1587","line":1704,"column":36,"nodeType":"1525","messageId":"1583","endLine":1704,"endColumn":37},{"ruleId":"1581","severity":1,"message":"1588","line":1704,"column":39,"nodeType":"1525","messageId":"1583","endLine":1704,"endColumn":40},{"ruleId":"1581","severity":1,"message":"1589","line":1721,"column":15,"nodeType":"1525","messageId":"1583","endLine":1721,"endColumn":16},{"ruleId":"1581","severity":1,"message":"1590","line":1721,"column":18,"nodeType":"1525","messageId":"1583","endLine":1721,"endColumn":19},{"ruleId":"1581","severity":1,"message":"1591","line":1721,"column":21,"nodeType":"1525","messageId":"1583","endLine":1721,"endColumn":22},{"ruleId":"1581","severity":1,"message":"1582","line":1721,"column":24,"nodeType":"1525","messageId":"1583","endLine":1721,"endColumn":25},{"ruleId":"1581","severity":1,"message":"1584","line":1721,"column":27,"nodeType":"1525","messageId":"1583","endLine":1721,"endColumn":28},{"ruleId":"1581","severity":1,"message":"1585","line":1721,"column":30,"nodeType":"1525","messageId":"1583","endLine":1721,"endColumn":31},{"ruleId":"1581","severity":1,"message":"1586","line":1721,"column":33,"nodeType":"1525","messageId":"1583","endLine":1721,"endColumn":34},{"ruleId":"1581","severity":1,"message":"1587","line":1721,"column":36,"nodeType":"1525","messageId":"1583","endLine":1721,"endColumn":37},{"ruleId":"1581","severity":1,"message":"1588","line":1721,"column":39,"nodeType":"1525","messageId":"1583","endLine":1721,"endColumn":40},{"ruleId":"1581","severity":1,"message":"1589","line":1724,"column":15,"nodeType":"1525","messageId":"1583","endLine":1724,"endColumn":16},{"ruleId":"1581","severity":1,"message":"1590","line":1724,"column":18,"nodeType":"1525","messageId":"1583","endLine":1724,"endColumn":19},{"ruleId":"1581","severity":1,"message":"1591","line":1724,"column":21,"nodeType":"1525","messageId":"1583","endLine":1724,"endColumn":22},{"ruleId":"1581","severity":1,"message":"1582","line":1724,"column":24,"nodeType":"1525","messageId":"1583","endLine":1724,"endColumn":25},{"ruleId":"1581","severity":1,"message":"1584","line":1724,"column":27,"nodeType":"1525","messageId":"1583","endLine":1724,"endColumn":28},{"ruleId":"1581","severity":1,"message":"1585","line":1724,"column":30,"nodeType":"1525","messageId":"1583","endLine":1724,"endColumn":31},{"ruleId":"1581","severity":1,"message":"1586","line":1724,"column":33,"nodeType":"1525","messageId":"1583","endLine":1724,"endColumn":34},{"ruleId":"1581","severity":1,"message":"1587","line":1724,"column":36,"nodeType":"1525","messageId":"1583","endLine":1724,"endColumn":37},{"ruleId":"1581","severity":1,"message":"1588","line":1724,"column":39,"nodeType":"1525","messageId":"1583","endLine":1724,"endColumn":40},{"ruleId":"1533","severity":2,"message":"1534","line":1845,"column":15,"nodeType":"1535","messageId":"1536","endLine":1845,"endColumn":17,"suggestions":"1592"},{"ruleId":"1558","severity":2,"message":"1559","line":2377,"column":11,"nodeType":"1560","messageId":"1561","endLine":2377,"endColumn":25},{"ruleId":"1593","severity":2,"message":"1594","line":2396,"column":41,"nodeType":"1565","messageId":"1595","endLine":2396,"endColumn":50},{"ruleId":"1593","severity":2,"message":"1594","line":2404,"column":42,"nodeType":"1565","messageId":"1595","endLine":2404,"endColumn":51},{"ruleId":"1551","severity":2,"message":"1596","line":2407,"column":30,"nodeType":"1553","messageId":"1536","endLine":2407,"endColumn":32},{"ruleId":"1571","severity":2,"message":"1572","line":2541,"column":10,"nodeType":"1573","messageId":"1574","endLine":2541,"endColumn":19},{"ruleId":"1558","severity":2,"message":"1559","line":2970,"column":24,"nodeType":"1560","messageId":"1561","endLine":2970,"endColumn":38},{"ruleId":"1597","severity":2,"message":"1598","line":3158,"column":13,"nodeType":"1599","messageId":"1600","endLine":3158,"endColumn":28},{"ruleId":"1597","severity":2,"message":"1598","line":3174,"column":13,"nodeType":"1599","messageId":"1600","endLine":3174,"endColumn":29},{"ruleId":"1571","severity":2,"message":"1572","line":3267,"column":20,"nodeType":"1573","messageId":"1574","endLine":3267,"endColumn":39},{"ruleId":"1597","severity":2,"message":"1598","line":3367,"column":11,"nodeType":"1599","messageId":"1600","endLine":3367,"endColumn":26},{"ruleId":"1601","severity":2,"message":"1602","line":3455,"column":10,"nodeType":"1565","messageId":"1536","endLine":3455,"endColumn":26},{"ruleId":"1551","severity":2,"message":"1603","line":3468,"column":17,"nodeType":"1557","messageId":"1536","endLine":3468,"endColumn":19},{"ruleId":"1597","severity":2,"message":"1598","line":4068,"column":15,"nodeType":"1599","messageId":"1600","endLine":4076,"endColumn":24},{"ruleId":"1544","severity":2,"message":"1545","line":4105,"column":16,"nodeType":"1565","messageId":"1536","endLine":4105,"endColumn":17},{"ruleId":"1571","severity":2,"message":"1572","line":4143,"column":15,"nodeType":"1573","messageId":"1574","endLine":4143,"endColumn":36},{"ruleId":"1571","severity":2,"message":"1572","line":4196,"column":17,"nodeType":"1573","messageId":"1574","endLine":4196,"endColumn":30},{"ruleId":"1571","severity":2,"message":"1572","line":4618,"column":14,"nodeType":"1573","messageId":"1574","endLine":4618,"endColumn":35},{"ruleId":"1551","severity":2,"message":"1604","line":4841,"column":17,"nodeType":"1557","messageId":"1536","endLine":4841,"endColumn":19},{"ruleId":"1551","severity":2,"message":"1605","line":4984,"column":17,"nodeType":"1557","messageId":"1536","endLine":4984,"endColumn":19},{"ruleId":"1533","severity":2,"message":"1534","line":5068,"column":17,"nodeType":"1535","messageId":"1536","endLine":5069,"endColumn":10,"suggestions":"1606"},{"ruleId":"1533","severity":2,"message":"1534","line":5069,"column":19,"nodeType":"1535","messageId":"1536","endLine":5070,"endColumn":10,"suggestions":"1607"},{"ruleId":"1551","severity":2,"message":"1608","line":5171,"column":37,"nodeType":"1553","messageId":"1536","endLine":5171,"endColumn":39},{"ruleId":"1571","severity":2,"message":"1572","line":5526,"column":14,"nodeType":"1573","messageId":"1574","endLine":5526,"endColumn":47},{"ruleId":"1571","severity":2,"message":"1572","line":5572,"column":12,"nodeType":"1573","messageId":"1574","endLine":5572,"endColumn":51},{"ruleId":"1551","severity":2,"message":"1562","line":6008,"column":20,"nodeType":"1553","messageId":"1536","endLine":6008,"endColumn":22},{"ruleId":"1558","severity":2,"message":"1559","line":6035,"column":16,"nodeType":"1560","messageId":"1561","endLine":6035,"endColumn":30},{"ruleId":"1558","severity":2,"message":"1559","line":6035,"column":39,"nodeType":"1560","messageId":"1561","endLine":6035,"endColumn":53},{"ruleId":"1558","severity":2,"message":"1559","line":6038,"column":28,"nodeType":"1560","messageId":"1561","endLine":6038,"endColumn":42},{"ruleId":"1558","severity":2,"message":"1559","line":6045,"column":19,"nodeType":"1560","messageId":"1561","endLine":6045,"endColumn":33},{"ruleId":"1558","severity":2,"message":"1559","line":6052,"column":13,"nodeType":"1560","messageId":"1561","endLine":6052,"endColumn":27},{"ruleId":"1558","severity":2,"message":"1559","line":6057,"column":20,"nodeType":"1560","messageId":"1561","endLine":6057,"endColumn":34},{"ruleId":"1558","severity":2,"message":"1559","line":6058,"column":27,"nodeType":"1560","messageId":"1561","endLine":6058,"endColumn":41},{"ruleId":"1558","severity":2,"message":"1559","line":6061,"column":19,"nodeType":"1560","messageId":"1561","endLine":6061,"endColumn":33},{"ruleId":"1558","severity":2,"message":"1559","line":6075,"column":21,"nodeType":"1560","messageId":"1561","endLine":6075,"endColumn":35},{"ruleId":"1558","severity":2,"message":"1559","line":6213,"column":21,"nodeType":"1560","messageId":"1561","endLine":6213,"endColumn":35},{"ruleId":"1558","severity":2,"message":"1559","line":6226,"column":24,"nodeType":"1560","messageId":"1561","endLine":6226,"endColumn":38},{"ruleId":"1558","severity":2,"message":"1559","line":6311,"column":23,"nodeType":"1560","messageId":"1561","endLine":6311,"endColumn":37},{"ruleId":"1558","severity":2,"message":"1559","line":6324,"column":27,"nodeType":"1560","messageId":"1561","endLine":6324,"endColumn":41},{"ruleId":"1533","severity":2,"message":"1534","line":6850,"column":15,"nodeType":"1535","messageId":"1536","endLine":6850,"endColumn":17,"suggestions":"1609"},{"ruleId":"1597","severity":2,"message":"1598","line":6854,"column":7,"nodeType":"1599","messageId":"1600","endLine":6869,"endColumn":14},{"ruleId":"1558","severity":2,"message":"1559","line":7164,"column":42,"nodeType":"1560","messageId":"1561","endLine":7164,"endColumn":56},{"ruleId":"1581","severity":1,"message":"1590","line":7245,"column":18,"nodeType":"1525","messageId":"1583","endLine":7245,"endColumn":19},{"ruleId":"1581","severity":1,"message":"1591","line":7245,"column":21,"nodeType":"1525","messageId":"1583","endLine":7245,"endColumn":22},{"ruleId":"1581","severity":1,"message":"1590","line":7248,"column":18,"nodeType":"1525","messageId":"1583","endLine":7248,"endColumn":19},{"ruleId":"1581","severity":1,"message":"1591","line":7248,"column":21,"nodeType":"1525","messageId":"1583","endLine":7248,"endColumn":22},{"ruleId":"1544","severity":2,"message":"1545","line":7559,"column":14,"nodeType":"1565","messageId":"1536","endLine":7559,"endColumn":15},{"ruleId":"1544","severity":2,"message":"1545","line":7912,"column":14,"nodeType":"1565","messageId":"1536","endLine":7912,"endColumn":15},{"ruleId":"1544","severity":2,"message":"1545","line":7934,"column":12,"nodeType":"1565","messageId":"1536","endLine":7934,"endColumn":13},{"ruleId":"1533","severity":2,"message":"1534","line":8162,"column":21,"nodeType":"1535","messageId":"1536","endLine":8162,"endColumn":23,"suggestions":"1610"},{"ruleId":"1551","severity":2,"message":"1611","line":8850,"column":17,"nodeType":"1557","messageId":"1536","endLine":8850,"endColumn":19},{"ruleId":"1612","severity":2,"message":"1613","line":8985,"column":3,"nodeType":"1525","messageId":"1614","endLine":8985,"endColumn":5},{"ruleId":"1612","severity":2,"message":"1615","line":8986,"column":3,"nodeType":"1525","messageId":"1614","endLine":8986,"endColumn":5},{"ruleId":"1523","severity":2,"message":"1616","line":9021,"column":14,"nodeType":"1525","messageId":"1526","endLine":9021,"endColumn":44},{"ruleId":"1533","severity":2,"message":"1534","line":9025,"column":15,"nodeType":"1535","messageId":"1536","endLine":9025,"endColumn":17,"suggestions":"1617"},{"ruleId":"1523","severity":2,"message":"1616","line":9118,"column":16,"nodeType":"1525","messageId":"1526","endLine":9118,"endColumn":46},{"ruleId":"1523","severity":2,"message":"1616","line":9122,"column":9,"nodeType":"1525","messageId":"1526","endLine":9122,"endColumn":39},{"ruleId":"1612","severity":2,"message":"1618","line":9142,"column":8,"nodeType":"1525","messageId":"1614","endLine":9142,"endColumn":10},{"ruleId":"1533","severity":2,"message":"1534","line":9184,"column":15,"nodeType":"1535","messageId":"1536","endLine":9184,"endColumn":17,"suggestions":"1619"},{"ruleId":"1558","severity":2,"message":"1559","line":11045,"column":12,"nodeType":"1560","messageId":"1561","endLine":11045,"endColumn":26},{"ruleId":"1558","severity":2,"message":"1559","line":11048,"column":16,"nodeType":"1560","messageId":"1561","endLine":11048,"endColumn":30},{"ruleId":"1612","severity":2,"message":"1620","line":11218,"column":8,"nodeType":"1525","messageId":"1614","endLine":11218,"endColumn":10},{"ruleId":"1581","severity":1,"message":"1589","line":11505,"column":15,"nodeType":"1525","messageId":"1583","endLine":11505,"endColumn":16},{"ruleId":"1581","severity":1,"message":"1589","line":11509,"column":15,"nodeType":"1525","messageId":"1583","endLine":11509,"endColumn":16},{"ruleId":"1581","severity":1,"message":"1589","line":11513,"column":15,"nodeType":"1525","messageId":"1583","endLine":11513,"endColumn":16},{"ruleId":"1581","severity":1,"message":"1589","line":11517,"column":15,"nodeType":"1525","messageId":"1583","endLine":11517,"endColumn":16},{"ruleId":"1581","severity":1,"message":"1589","line":11621,"column":15,"nodeType":"1525","messageId":"1583","endLine":11621,"endColumn":16},{"ruleId":"1551","severity":2,"message":"1621","line":11667,"column":21,"nodeType":"1622","messageId":"1536","endLine":11667,"endColumn":23},{"ruleId":"1612","severity":2,"message":"1623","line":11731,"column":8,"nodeType":"1525","messageId":"1614","endLine":11731,"endColumn":10},{"ruleId":"1533","severity":2,"message":"1534","line":11826,"column":17,"nodeType":"1535","messageId":"1536","endLine":11826,"endColumn":19,"suggestions":"1624"},{"ruleId":"1523","severity":2,"message":"1625","line":12126,"column":44,"nodeType":"1525","messageId":"1526","endLine":12126,"endColumn":60},{"ruleId":"1523","severity":2,"message":"1625","line":12173,"column":40,"nodeType":"1525","messageId":"1526","endLine":12173,"endColumn":56},{"ruleId":"1551","severity":2,"message":"1621","line":12183,"column":26,"nodeType":"1622","messageId":"1536","endLine":12183,"endColumn":28},{"ruleId":"1523","severity":2,"message":"1625","line":12189,"column":36,"nodeType":"1525","messageId":"1526","endLine":12189,"endColumn":52},{"ruleId":"1533","severity":2,"message":"1534","line":12231,"column":15,"nodeType":"1535","messageId":"1536","endLine":12231,"endColumn":17,"suggestions":"1626"},{"ruleId":"1523","severity":2,"message":"1625","line":12399,"column":43,"nodeType":"1525","messageId":"1526","endLine":12399,"endColumn":59},{"ruleId":"1523","severity":2,"message":"1625","line":12443,"column":45,"nodeType":"1525","messageId":"1526","endLine":12443,"endColumn":61},{"ruleId":"1523","severity":2,"message":"1625","line":12457,"column":45,"nodeType":"1525","messageId":"1526","endLine":12457,"endColumn":61},{"ruleId":"1533","severity":2,"message":"1534","line":12553,"column":21,"nodeType":"1535","messageId":"1536","endLine":12553,"endColumn":23,"suggestions":"1627"},{"ruleId":"1533","severity":2,"message":"1534","line":12605,"column":17,"nodeType":"1535","messageId":"1536","endLine":12605,"endColumn":19,"suggestions":"1628"},{"ruleId":"1533","severity":2,"message":"1534","line":12626,"column":13,"nodeType":"1535","messageId":"1536","endLine":12626,"endColumn":15,"suggestions":"1629"},{"ruleId":"1533","severity":2,"message":"1534","line":12640,"column":13,"nodeType":"1535","messageId":"1536","endLine":12640,"endColumn":15,"suggestions":"1630"},{"ruleId":"1558","severity":2,"message":"1559","line":12666,"column":14,"nodeType":"1560","messageId":"1561","endLine":12666,"endColumn":28},{"ruleId":"1631","severity":2,"message":"1632","line":12671,"column":25,"nodeType":"1525","messageId":"1633","endLine":12671,"endColumn":26},{"ruleId":"1533","severity":2,"message":"1534","line":12680,"column":25,"nodeType":"1535","messageId":"1536","endLine":12680,"endColumn":27,"suggestions":"1634"},{"ruleId":"1631","severity":2,"message":"1632","line":12688,"column":25,"nodeType":"1525","messageId":"1633","endLine":12688,"endColumn":26},{"ruleId":"1533","severity":2,"message":"1534","line":12699,"column":25,"nodeType":"1535","messageId":"1536","endLine":12699,"endColumn":27,"suggestions":"1635"},{"ruleId":"1533","severity":2,"message":"1534","line":12791,"column":13,"nodeType":"1535","messageId":"1536","endLine":12791,"endColumn":15,"suggestions":"1636"},{"ruleId":"1523","severity":2,"message":"1637","line":12798,"column":56,"nodeType":"1525","messageId":"1526","endLine":12798,"endColumn":81},{"ruleId":"1533","severity":2,"message":"1534","line":12845,"column":15,"nodeType":"1535","messageId":"1536","endLine":12845,"endColumn":17,"suggestions":"1638"},{"ruleId":"1551","severity":2,"message":"1621","line":13028,"column":67,"nodeType":"1622","messageId":"1536","endLine":13028,"endColumn":69},{"ruleId":"1523","severity":2,"message":"1625","line":13295,"column":48,"nodeType":"1525","messageId":"1526","endLine":13295,"endColumn":64},{"ruleId":"1639","severity":2,"message":"1640","line":13511,"column":19,"nodeType":"1525","messageId":"1641","endLine":13511,"endColumn":20},{"ruleId":"1523","severity":2,"message":"1625","line":13620,"column":46,"nodeType":"1525","messageId":"1526","endLine":13620,"endColumn":62},{"ruleId":"1523","severity":2,"message":"1625","line":13789,"column":45,"nodeType":"1525","messageId":"1526","endLine":13789,"endColumn":61},{"ruleId":"1523","severity":2,"message":"1625","line":13798,"column":43,"nodeType":"1525","messageId":"1526","endLine":13798,"endColumn":59},{"ruleId":"1523","severity":2,"message":"1625","line":13856,"column":42,"nodeType":"1525","messageId":"1526","endLine":13856,"endColumn":58},{"ruleId":"1523","severity":2,"message":"1642","line":13893,"column":52,"nodeType":"1525","messageId":"1526","endLine":13893,"endColumn":70},{"ruleId":"1523","severity":2,"message":"1625","line":13912,"column":42,"nodeType":"1525","messageId":"1526","endLine":13912,"endColumn":58},{"ruleId":"1523","severity":2,"message":"1625","line":13985,"column":43,"nodeType":"1525","messageId":"1526","endLine":13985,"endColumn":59},{"ruleId":"1523","severity":2,"message":"1625","line":14015,"column":43,"nodeType":"1525","messageId":"1526","endLine":14015,"endColumn":59},{"ruleId":"1523","severity":2,"message":"1625","line":14170,"column":44,"nodeType":"1525","messageId":"1526","endLine":14170,"endColumn":60},{"ruleId":"1523","severity":2,"message":"1625","line":14180,"column":43,"nodeType":"1525","messageId":"1526","endLine":14180,"endColumn":59},{"ruleId":"1523","severity":2,"message":"1625","line":14216,"column":46,"nodeType":"1525","messageId":"1526","endLine":14216,"endColumn":62},{"ruleId":"1523","severity":2,"message":"1625","line":14222,"column":43,"nodeType":"1525","messageId":"1526","endLine":14222,"endColumn":59},{"ruleId":"1523","severity":2,"message":"1625","line":14334,"column":46,"nodeType":"1525","messageId":"1526","endLine":14334,"endColumn":62},{"ruleId":"1523","severity":2,"message":"1625","line":14352,"column":43,"nodeType":"1525","messageId":"1526","endLine":14352,"endColumn":59},{"ruleId":"1523","severity":2,"message":"1625","line":14364,"column":47,"nodeType":"1525","messageId":"1526","endLine":14364,"endColumn":63},{"ruleId":"1523","severity":2,"message":"1625","line":14372,"column":50,"nodeType":"1525","messageId":"1526","endLine":14372,"endColumn":66},{"ruleId":"1523","severity":2,"message":"1625","line":14380,"column":45,"nodeType":"1525","messageId":"1526","endLine":14380,"endColumn":61},{"ruleId":"1523","severity":2,"message":"1625","line":14383,"column":43,"nodeType":"1525","messageId":"1526","endLine":14383,"endColumn":59},{"ruleId":"1523","severity":2,"message":"1625","line":14403,"column":45,"nodeType":"1525","messageId":"1526","endLine":14403,"endColumn":61},{"ruleId":"1523","severity":2,"message":"1625","line":14436,"column":43,"nodeType":"1525","messageId":"1526","endLine":14436,"endColumn":59},{"ruleId":"1523","severity":2,"message":"1625","line":14439,"column":43,"nodeType":"1525","messageId":"1526","endLine":14439,"endColumn":59},{"ruleId":"1523","severity":2,"message":"1625","line":14448,"column":46,"nodeType":"1525","messageId":"1526","endLine":14448,"endColumn":62},{"ruleId":"1523","severity":2,"message":"1625","line":14451,"column":45,"nodeType":"1525","messageId":"1526","endLine":14451,"endColumn":61},{"ruleId":"1523","severity":2,"message":"1625","line":14472,"column":48,"nodeType":"1525","messageId":"1526","endLine":14472,"endColumn":64},{"ruleId":"1523","severity":2,"message":"1625","line":14482,"column":41,"nodeType":"1525","messageId":"1526","endLine":14482,"endColumn":57},{"ruleId":"1523","severity":2,"message":"1625","line":14512,"column":52,"nodeType":"1525","messageId":"1526","endLine":14512,"endColumn":68},{"ruleId":"1523","severity":2,"message":"1625","line":14515,"column":52,"nodeType":"1525","messageId":"1526","endLine":14515,"endColumn":68},{"ruleId":"1523","severity":2,"message":"1625","line":14522,"column":48,"nodeType":"1525","messageId":"1526","endLine":14522,"endColumn":64},{"ruleId":"1523","severity":2,"message":"1625","line":14532,"column":46,"nodeType":"1525","messageId":"1526","endLine":14532,"endColumn":62},{"ruleId":"1523","severity":2,"message":"1625","line":14542,"column":44,"nodeType":"1525","messageId":"1526","endLine":14542,"endColumn":60},{"ruleId":"1523","severity":2,"message":"1625","line":14550,"column":44,"nodeType":"1525","messageId":"1526","endLine":14550,"endColumn":60},{"ruleId":"1523","severity":2,"message":"1625","line":14563,"column":42,"nodeType":"1525","messageId":"1526","endLine":14563,"endColumn":58},{"ruleId":"1523","severity":2,"message":"1625","line":14717,"column":43,"nodeType":"1525","messageId":"1526","endLine":14717,"endColumn":59},{"ruleId":"1533","severity":2,"message":"1534","line":14783,"column":13,"nodeType":"1535","messageId":"1536","endLine":14783,"endColumn":15,"suggestions":"1643"},{"ruleId":"1523","severity":2,"message":"1625","line":14859,"column":43,"nodeType":"1525","messageId":"1526","endLine":14859,"endColumn":59},{"ruleId":"1523","severity":2,"message":"1625","line":14864,"column":43,"nodeType":"1525","messageId":"1526","endLine":14864,"endColumn":59},{"ruleId":"1523","severity":2,"message":"1625","line":14897,"column":43,"nodeType":"1525","messageId":"1526","endLine":14897,"endColumn":59},{"ruleId":"1523","severity":2,"message":"1625","line":14912,"column":43,"nodeType":"1525","messageId":"1526","endLine":14912,"endColumn":59},{"ruleId":"1523","severity":2,"message":"1625","line":14917,"column":45,"nodeType":"1525","messageId":"1526","endLine":14917,"endColumn":61},{"ruleId":"1523","severity":2,"message":"1625","line":14958,"column":45,"nodeType":"1525","messageId":"1526","endLine":14958,"endColumn":61},{"ruleId":"1581","severity":1,"message":"1582","line":14996,"column":30,"nodeType":"1525","messageId":"1583","endLine":14996,"endColumn":31},{"ruleId":"1523","severity":2,"message":"1625","line":14999,"column":44,"nodeType":"1525","messageId":"1526","endLine":14999,"endColumn":60},{"ruleId":"1523","severity":2,"message":"1625","line":15057,"column":48,"nodeType":"1525","messageId":"1526","endLine":15057,"endColumn":64},{"ruleId":"1523","severity":2,"message":"1625","line":15136,"column":47,"nodeType":"1525","messageId":"1526","endLine":15136,"endColumn":63},{"ruleId":"1523","severity":2,"message":"1625","line":15140,"column":42,"nodeType":"1525","messageId":"1526","endLine":15140,"endColumn":58},{"ruleId":"1523","severity":2,"message":"1625","line":15181,"column":41,"nodeType":"1525","messageId":"1526","endLine":15181,"endColumn":57},{"ruleId":"1523","severity":2,"message":"1625","line":15220,"column":51,"nodeType":"1525","messageId":"1526","endLine":15220,"endColumn":67},{"ruleId":"1523","severity":2,"message":"1625","line":15236,"column":49,"nodeType":"1525","messageId":"1526","endLine":15236,"endColumn":65},{"ruleId":"1533","severity":2,"message":"1534","line":15270,"column":15,"nodeType":"1535","messageId":"1536","endLine":15270,"endColumn":17,"suggestions":"1644"},{"ruleId":"1523","severity":2,"message":"1625","line":15324,"column":44,"nodeType":"1525","messageId":"1526","endLine":15324,"endColumn":60},{"ruleId":"1523","severity":2,"message":"1625","line":15329,"column":44,"nodeType":"1525","messageId":"1526","endLine":15329,"endColumn":60},{"ruleId":"1523","severity":2,"message":"1625","line":15334,"column":44,"nodeType":"1525","messageId":"1526","endLine":15334,"endColumn":60},{"ruleId":"1523","severity":2,"message":"1625","line":15339,"column":44,"nodeType":"1525","messageId":"1526","endLine":15339,"endColumn":60},{"ruleId":"1523","severity":2,"message":"1625","line":15346,"column":44,"nodeType":"1525","messageId":"1526","endLine":15346,"endColumn":60},{"ruleId":"1523","severity":2,"message":"1625","line":15379,"column":45,"nodeType":"1525","messageId":"1526","endLine":15379,"endColumn":61},{"ruleId":"1533","severity":2,"message":"1534","line":15389,"column":13,"nodeType":"1535","messageId":"1536","endLine":15389,"endColumn":15,"suggestions":"1645"},{"ruleId":"1533","severity":2,"message":"1534","line":15405,"column":15,"nodeType":"1535","messageId":"1536","endLine":15405,"endColumn":17,"suggestions":"1646"},{"ruleId":"1523","severity":2,"message":"1625","line":15409,"column":43,"nodeType":"1525","messageId":"1526","endLine":15409,"endColumn":59},{"ruleId":"1533","severity":2,"message":"1534","line":15461,"column":13,"nodeType":"1535","messageId":"1536","endLine":15461,"endColumn":15,"suggestions":"1647"},{"ruleId":"1533","severity":2,"message":"1534","line":15470,"column":13,"nodeType":"1535","messageId":"1536","endLine":15470,"endColumn":15,"suggestions":"1648"},{"ruleId":"1533","severity":2,"message":"1534","line":15518,"column":13,"nodeType":"1535","messageId":"1536","endLine":15518,"endColumn":15,"suggestions":"1649"},{"ruleId":"1523","severity":2,"message":"1625","line":15641,"column":44,"nodeType":"1525","messageId":"1526","endLine":15641,"endColumn":60},{"ruleId":"1523","severity":2,"message":"1625","line":15788,"column":43,"nodeType":"1525","messageId":"1526","endLine":15788,"endColumn":59},{"ruleId":"1523","severity":2,"message":"1625","line":15807,"column":43,"nodeType":"1525","messageId":"1526","endLine":15807,"endColumn":59},{"ruleId":"1523","severity":2,"message":"1625","line":15812,"column":43,"nodeType":"1525","messageId":"1526","endLine":15812,"endColumn":59},{"ruleId":"1523","severity":2,"message":"1625","line":15816,"column":41,"nodeType":"1525","messageId":"1526","endLine":15816,"endColumn":57},{"ruleId":"1523","severity":2,"message":"1625","line":15835,"column":43,"nodeType":"1525","messageId":"1526","endLine":15835,"endColumn":59},{"ruleId":"1533","severity":2,"message":"1534","line":16016,"column":15,"nodeType":"1535","messageId":"1536","endLine":16016,"endColumn":17,"suggestions":"1650"},{"ruleId":"1523","severity":2,"message":"1625","line":16063,"column":39,"nodeType":"1525","messageId":"1526","endLine":16063,"endColumn":55},{"ruleId":"1631","severity":2,"message":"1632","line":16170,"column":13,"nodeType":"1525","messageId":"1633","endLine":16170,"endColumn":14},{"ruleId":"1558","severity":2,"message":"1559","line":16198,"column":10,"nodeType":"1560","messageId":"1561","endLine":16198,"endColumn":24},{"ruleId":"1533","severity":2,"message":"1534","line":16210,"column":19,"nodeType":"1535","messageId":"1536","endLine":16210,"endColumn":21,"suggestions":"1651"},{"ruleId":"1533","severity":2,"message":"1534","line":16234,"column":19,"nodeType":"1535","messageId":"1536","endLine":16234,"endColumn":21,"suggestions":"1652"},{"ruleId":"1523","severity":2,"message":"1625","line":16328,"column":51,"nodeType":"1525","messageId":"1526","endLine":16328,"endColumn":67},{"ruleId":"1639","severity":2,"message":"1653","line":16376,"column":41,"nodeType":"1525","messageId":"1641","endLine":16376,"endColumn":42},{"ruleId":"1639","severity":2,"message":"1654","line":16376,"column":50,"nodeType":"1525","messageId":"1641","endLine":16376,"endColumn":51},{"ruleId":"1639","severity":2,"message":"1653","line":16396,"column":11,"nodeType":"1525","messageId":"1641","endLine":16396,"endColumn":12},{"ruleId":"1639","severity":2,"message":"1654","line":16396,"column":20,"nodeType":"1525","messageId":"1641","endLine":16396,"endColumn":21},{"ruleId":"1523","severity":2,"message":"1655","line":16429,"column":24,"nodeType":"1525","messageId":"1526","endLine":16429,"endColumn":42},{"ruleId":"1523","severity":2,"message":"1625","line":16448,"column":41,"nodeType":"1525","messageId":"1526","endLine":16448,"endColumn":57},{"ruleId":"1533","severity":2,"message":"1534","line":16580,"column":15,"nodeType":"1535","messageId":"1536","endLine":16580,"endColumn":17,"suggestions":"1656"},{"ruleId":"1601","severity":2,"message":"1657","line":16622,"column":14,"nodeType":"1565","messageId":"1536","endLine":16622,"endColumn":34},{"ruleId":"1601","severity":2,"message":"1657","line":16623,"column":10,"nodeType":"1565","messageId":"1536","endLine":16623,"endColumn":30},{"ruleId":"1658","severity":2,"message":"1659","line":16797,"column":9,"nodeType":"1660","messageId":"1536","endLine":16798,"endColumn":20},{"ruleId":"1658","severity":2,"message":"1659","line":16799,"column":9,"nodeType":"1660","messageId":"1536","endLine":16799,"endColumn":19},{"ruleId":"1658","severity":2,"message":"1659","line":16901,"column":9,"nodeType":"1660","messageId":"1536","endLine":16901,"endColumn":55},{"ruleId":"1658","severity":2,"message":"1659","line":16902,"column":9,"nodeType":"1660","messageId":"1536","endLine":16902,"endColumn":30},{"ruleId":"1658","severity":2,"message":"1659","line":16903,"column":9,"nodeType":"1660","messageId":"1536","endLine":16904,"endColumn":43},{"ruleId":"1581","severity":1,"message":"1591","line":17274,"column":21,"nodeType":"1525","messageId":"1583","endLine":17274,"endColumn":22},{"ruleId":"1558","severity":2,"message":"1559","line":17374,"column":25,"nodeType":"1560","messageId":"1561","endLine":17374,"endColumn":39},{"ruleId":"1581","severity":1,"message":"1585","line":17413,"column":22,"nodeType":"1525","messageId":"1583","endLine":17413,"endColumn":23},{"ruleId":"1631","severity":2,"message":"1632","line":17417,"column":9,"nodeType":"1525","messageId":"1633","endLine":17417,"endColumn":10},{"ruleId":"1551","severity":2,"message":"1621","line":17450,"column":35,"nodeType":"1622","messageId":"1536","endLine":17450,"endColumn":37},{"ruleId":"1551","severity":2,"message":"1621","line":17465,"column":20,"nodeType":"1622","messageId":"1536","endLine":17465,"endColumn":22},{"ruleId":"1533","severity":2,"message":"1534","line":17970,"column":19,"nodeType":"1535","messageId":"1536","endLine":17970,"endColumn":21,"suggestions":"1661"},{"ruleId":"1533","severity":2,"message":"1534","line":17981,"column":13,"nodeType":"1535","messageId":"1536","endLine":17981,"endColumn":15,"suggestions":"1662"},{"ruleId":"1551","severity":2,"message":"1621","line":18015,"column":42,"nodeType":"1622","messageId":"1536","endLine":18015,"endColumn":44},{"ruleId":"1551","severity":2,"message":"1621","line":18064,"column":49,"nodeType":"1622","messageId":"1536","endLine":18064,"endColumn":51},{"ruleId":"1551","severity":2,"message":"1621","line":18247,"column":70,"nodeType":"1622","messageId":"1536","endLine":18247,"endColumn":72},{"ruleId":"1551","severity":2,"message":"1621","line":18393,"column":26,"nodeType":"1622","messageId":"1536","endLine":18393,"endColumn":28},{"ruleId":"1551","severity":2,"message":"1621","line":18483,"column":26,"nodeType":"1622","messageId":"1536","endLine":18483,"endColumn":28},{"ruleId":"1551","severity":2,"message":"1621","line":18494,"column":42,"nodeType":"1622","messageId":"1536","endLine":18494,"endColumn":44},{"ruleId":"1533","severity":2,"message":"1534","line":18501,"column":15,"nodeType":"1535","messageId":"1536","endLine":18501,"endColumn":17,"suggestions":"1663"},{"ruleId":"1631","severity":2,"message":"1632","line":18545,"column":13,"nodeType":"1525","messageId":"1633","endLine":18545,"endColumn":14},{"ruleId":"1631","severity":2,"message":"1632","line":18579,"column":15,"nodeType":"1525","messageId":"1633","endLine":18579,"endColumn":16},{"ruleId":"1664","severity":2,"message":"1665","line":18609,"column":23,"nodeType":"1525","messageId":"1666","endLine":18609,"endColumn":24},{"ruleId":"1581","severity":1,"message":"1585","line":18615,"column":30,"nodeType":"1525","messageId":"1583","endLine":18615,"endColumn":31},{"ruleId":"1581","severity":1,"message":"1667","line":18790,"column":21,"nodeType":"1525","messageId":"1583","endLine":18790,"endColumn":22},{"ruleId":"1533","severity":2,"message":"1534","line":19374,"column":17,"nodeType":"1535","messageId":"1536","endLine":19374,"endColumn":19,"suggestions":"1668"},{"ruleId":"1523","severity":2,"message":"1625","line":19441,"column":41,"nodeType":"1525","messageId":"1526","endLine":19441,"endColumn":57},{"ruleId":"1523","severity":2,"message":"1625","line":19452,"column":49,"nodeType":"1525","messageId":"1526","endLine":19452,"endColumn":65},{"ruleId":"1523","severity":2,"message":"1625","line":19538,"column":43,"nodeType":"1525","messageId":"1526","endLine":19538,"endColumn":59},{"ruleId":"1523","severity":2,"message":"1625","line":19554,"column":43,"nodeType":"1525","messageId":"1526","endLine":19554,"endColumn":59},{"ruleId":"1523","severity":2,"message":"1625","line":19563,"column":44,"nodeType":"1525","messageId":"1526","endLine":19563,"endColumn":60},{"ruleId":"1523","severity":2,"message":"1625","line":19568,"column":43,"nodeType":"1525","messageId":"1526","endLine":19568,"endColumn":59},{"ruleId":"1523","severity":2,"message":"1625","line":19572,"column":41,"nodeType":"1525","messageId":"1526","endLine":19572,"endColumn":57},{"ruleId":"1533","severity":2,"message":"1534","line":19584,"column":15,"nodeType":"1535","messageId":"1536","endLine":19584,"endColumn":17,"suggestions":"1669"},{"ruleId":"1533","severity":2,"message":"1534","line":19602,"column":15,"nodeType":"1535","messageId":"1536","endLine":19602,"endColumn":17,"suggestions":"1670"},{"ruleId":"1523","severity":2,"message":"1625","line":19631,"column":41,"nodeType":"1525","messageId":"1526","endLine":19631,"endColumn":57},{"ruleId":"1523","severity":2,"message":"1625","line":19659,"column":45,"nodeType":"1525","messageId":"1526","endLine":19659,"endColumn":61},{"ruleId":"1523","severity":2,"message":"1625","line":19682,"column":41,"nodeType":"1525","messageId":"1526","endLine":19682,"endColumn":57},{"ruleId":"1523","severity":2,"message":"1625","line":19849,"column":45,"nodeType":"1525","messageId":"1526","endLine":19849,"endColumn":61},{"ruleId":"1523","severity":2,"message":"1625","line":19856,"column":43,"nodeType":"1525","messageId":"1526","endLine":19856,"endColumn":59},{"ruleId":"1523","severity":2,"message":"1625","line":19924,"column":46,"nodeType":"1525","messageId":"1526","endLine":19924,"endColumn":62},{"ruleId":"1533","severity":2,"message":"1534","line":20191,"column":15,"nodeType":"1535","messageId":"1536","endLine":20191,"endColumn":17,"suggestions":"1671"},{"ruleId":"1523","severity":2,"message":"1625","line":20274,"column":41,"nodeType":"1525","messageId":"1526","endLine":20274,"endColumn":57},{"ruleId":"1523","severity":2,"message":"1625","line":20376,"column":41,"nodeType":"1525","messageId":"1526","endLine":20376,"endColumn":57},{"ruleId":"1533","severity":2,"message":"1534","line":20462,"column":13,"nodeType":"1535","messageId":"1536","endLine":20462,"endColumn":15,"suggestions":"1672"},{"ruleId":"1523","severity":2,"message":"1625","line":20470,"column":43,"nodeType":"1525","messageId":"1526","endLine":20470,"endColumn":59},{"ruleId":"1533","severity":2,"message":"1534","line":20525,"column":17,"nodeType":"1535","messageId":"1536","endLine":20525,"endColumn":19,"suggestions":"1673"},{"ruleId":"1523","severity":2,"message":"1625","line":20710,"column":43,"nodeType":"1525","messageId":"1526","endLine":20710,"endColumn":59},{"ruleId":"1523","severity":2,"message":"1625","line":20812,"column":43,"nodeType":"1525","messageId":"1526","endLine":20812,"endColumn":59},{"ruleId":"1533","severity":2,"message":"1534","line":20832,"column":15,"nodeType":"1535","messageId":"1536","endLine":20832,"endColumn":17,"suggestions":"1674"},{"ruleId":"1523","severity":2,"message":"1625","line":20857,"column":45,"nodeType":"1525","messageId":"1526","endLine":20857,"endColumn":61},{"ruleId":"1533","severity":2,"message":"1534","line":20866,"column":19,"nodeType":"1535","messageId":"1536","endLine":20866,"endColumn":21,"suggestions":"1675"},{"ruleId":"1523","severity":2,"message":"1625","line":21044,"column":48,"nodeType":"1525","messageId":"1526","endLine":21044,"endColumn":64},{"ruleId":"1523","severity":2,"message":"1625","line":21136,"column":41,"nodeType":"1525","messageId":"1526","endLine":21136,"endColumn":57},{"ruleId":"1523","severity":2,"message":"1625","line":21138,"column":43,"nodeType":"1525","messageId":"1526","endLine":21138,"endColumn":59},{"ruleId":"1523","severity":2,"message":"1625","line":21216,"column":43,"nodeType":"1525","messageId":"1526","endLine":21216,"endColumn":59},{"ruleId":"1523","severity":2,"message":"1625","line":21224,"column":43,"nodeType":"1525","messageId":"1526","endLine":21224,"endColumn":59},{"ruleId":"1523","severity":2,"message":"1625","line":21279,"column":43,"nodeType":"1525","messageId":"1526","endLine":21279,"endColumn":59},{"ruleId":"1523","severity":2,"message":"1625","line":21314,"column":47,"nodeType":"1525","messageId":"1526","endLine":21314,"endColumn":63},{"ruleId":"1523","severity":2,"message":"1625","line":21321,"column":47,"nodeType":"1525","messageId":"1526","endLine":21321,"endColumn":63},{"ruleId":"1523","severity":2,"message":"1625","line":21334,"column":47,"nodeType":"1525","messageId":"1526","endLine":21334,"endColumn":63},{"ruleId":"1523","severity":2,"message":"1625","line":21585,"column":48,"nodeType":"1525","messageId":"1526","endLine":21585,"endColumn":64},{"ruleId":"1523","severity":2,"message":"1625","line":21594,"column":43,"nodeType":"1525","messageId":"1526","endLine":21594,"endColumn":59},{"ruleId":"1533","severity":2,"message":"1534","line":21664,"column":15,"nodeType":"1535","messageId":"1536","endLine":21664,"endColumn":17,"suggestions":"1676"},{"ruleId":"1551","severity":2,"message":"1621","line":21801,"column":18,"nodeType":"1622","messageId":"1536","endLine":21801,"endColumn":20},{"ruleId":"1523","severity":2,"message":"1625","line":21845,"column":44,"nodeType":"1525","messageId":"1526","endLine":21845,"endColumn":60},{"ruleId":"1523","severity":2,"message":"1625","line":21855,"column":44,"nodeType":"1525","messageId":"1526","endLine":21855,"endColumn":60},{"ruleId":"1523","severity":2,"message":"1625","line":21867,"column":42,"nodeType":"1525","messageId":"1526","endLine":21867,"endColumn":58},{"ruleId":"1523","severity":2,"message":"1625","line":21876,"column":40,"nodeType":"1525","messageId":"1526","endLine":21876,"endColumn":56},{"ruleId":"1523","severity":2,"message":"1625","line":21901,"column":52,"nodeType":"1525","messageId":"1526","endLine":21901,"endColumn":68},{"ruleId":"1523","severity":2,"message":"1625","line":21906,"column":54,"nodeType":"1525","messageId":"1526","endLine":21906,"endColumn":70},{"ruleId":"1523","severity":2,"message":"1625","line":21923,"column":44,"nodeType":"1525","messageId":"1526","endLine":21923,"endColumn":60},{"ruleId":"1523","severity":2,"message":"1625","line":21941,"column":46,"nodeType":"1525","messageId":"1526","endLine":21941,"endColumn":62},{"ruleId":"1523","severity":2,"message":"1625","line":22053,"column":42,"nodeType":"1525","messageId":"1526","endLine":22053,"endColumn":58},{"ruleId":"1523","severity":2,"message":"1625","line":22061,"column":44,"nodeType":"1525","messageId":"1526","endLine":22061,"endColumn":60},{"ruleId":"1581","severity":1,"message":"1677","line":22082,"column":41,"nodeType":"1525","messageId":"1583","endLine":22082,"endColumn":42},{"ruleId":"1533","severity":2,"message":"1534","line":22195,"column":17,"nodeType":"1535","messageId":"1536","endLine":22195,"endColumn":19,"suggestions":"1678"},{"ruleId":"1523","severity":2,"message":"1625","line":22200,"column":41,"nodeType":"1525","messageId":"1526","endLine":22200,"endColumn":57},{"ruleId":"1523","severity":2,"message":"1625","line":22224,"column":50,"nodeType":"1525","messageId":"1526","endLine":22224,"endColumn":66},{"ruleId":"1523","severity":2,"message":"1625","line":22302,"column":43,"nodeType":"1525","messageId":"1526","endLine":22302,"endColumn":59},{"ruleId":"1523","severity":2,"message":"1625","line":22332,"column":45,"nodeType":"1525","messageId":"1526","endLine":22332,"endColumn":61},{"ruleId":"1523","severity":2,"message":"1625","line":22336,"column":43,"nodeType":"1525","messageId":"1526","endLine":22336,"endColumn":59},{"ruleId":"1523","severity":2,"message":"1625","line":22359,"column":45,"nodeType":"1525","messageId":"1526","endLine":22359,"endColumn":61},{"ruleId":"1523","severity":2,"message":"1625","line":22372,"column":45,"nodeType":"1525","messageId":"1526","endLine":22372,"endColumn":61},{"ruleId":"1523","severity":2,"message":"1625","line":22379,"column":45,"nodeType":"1525","messageId":"1526","endLine":22379,"endColumn":61},{"ruleId":"1581","severity":1,"message":"1590","line":22685,"column":51,"nodeType":"1525","messageId":"1583","endLine":22685,"endColumn":52},{"ruleId":"1581","severity":1,"message":"1679","line":22797,"column":29,"nodeType":"1525","messageId":"1583","endLine":22797,"endColumn":30},{"ruleId":"1581","severity":1,"message":"1680","line":22856,"column":22,"nodeType":"1525","messageId":"1583","endLine":22856,"endColumn":23},{"ruleId":"1581","severity":1,"message":"1681","line":22863,"column":22,"nodeType":"1525","messageId":"1583","endLine":22863,"endColumn":23},{"ruleId":"1581","severity":1,"message":"1679","line":22978,"column":26,"nodeType":"1525","messageId":"1583","endLine":22978,"endColumn":27},{"ruleId":"1558","severity":2,"message":"1559","line":23238,"column":24,"nodeType":"1560","messageId":"1561","endLine":23238,"endColumn":38},{"ruleId":"1551","severity":2,"message":"1621","line":24398,"column":32,"nodeType":"1622","messageId":"1536","endLine":24398,"endColumn":34},{"ruleId":"1581","severity":1,"message":"1591","line":24429,"column":21,"nodeType":"1525","messageId":"1583","endLine":24429,"endColumn":22},{"ruleId":"1581","severity":1,"message":"1591","line":24459,"column":21,"nodeType":"1525","messageId":"1583","endLine":24459,"endColumn":22},{"ruleId":"1533","severity":2,"message":"1534","line":24529,"column":23,"nodeType":"1535","messageId":"1536","endLine":24529,"endColumn":25,"suggestions":"1682"},{"ruleId":"1558","severity":2,"message":"1559","line":24696,"column":13,"nodeType":"1560","messageId":"1561","endLine":24696,"endColumn":27},{"ruleId":"1558","severity":2,"message":"1559","line":24697,"column":13,"nodeType":"1560","messageId":"1561","endLine":24697,"endColumn":27},{"ruleId":"1597","severity":2,"message":"1598","line":25450,"column":11,"nodeType":"1599","messageId":"1600","endLine":25467,"endColumn":18},{"ruleId":"1597","severity":2,"message":"1598","line":25898,"column":11,"nodeType":"1599","messageId":"1600","endLine":25910,"endColumn":18},{"ruleId":"1551","severity":2,"message":"1621","line":26523,"column":40,"nodeType":"1622","messageId":"1536","endLine":26523,"endColumn":42},{"ruleId":"1581","severity":1,"message":"1683","line":26658,"column":48,"nodeType":"1525","messageId":"1583","endLine":26658,"endColumn":49},{"ruleId":"1581","severity":1,"message":"1684","line":26668,"column":50,"nodeType":"1525","messageId":"1583","endLine":26668,"endColumn":51},{"ruleId":"1551","severity":2,"message":"1685","line":26688,"column":17,"nodeType":"1557","messageId":"1536","endLine":26688,"endColumn":19},{"ruleId":"1551","severity":2,"message":"1686","line":26769,"column":23,"nodeType":"1622","messageId":"1536","endLine":26769,"endColumn":25},{"ruleId":"1551","severity":2,"message":"1686","line":26780,"column":23,"nodeType":"1622","messageId":"1536","endLine":26780,"endColumn":25},{"ruleId":"1567","severity":2,"message":"1687","line":27376,"column":43,"nodeType":"1565","messageId":"1569","endLine":27376,"endColumn":44,"suggestions":"1688"},{"ruleId":"1567","severity":2,"message":"1687","line":27376,"column":65,"nodeType":"1565","messageId":"1569","endLine":27376,"endColumn":66,"suggestions":"1689"},{"ruleId":"1567","severity":2,"message":"1690","line":27376,"column":76,"nodeType":"1565","messageId":"1569","endLine":27376,"endColumn":77,"suggestions":"1691"},{"ruleId":"1567","severity":2,"message":"1692","line":27376,"column":78,"nodeType":"1565","messageId":"1569","endLine":27376,"endColumn":79,"suggestions":"1693"},{"ruleId":"1567","severity":2,"message":"1687","line":27376,"column":88,"nodeType":"1565","messageId":"1569","endLine":27376,"endColumn":89,"suggestions":"1694"},{"ruleId":"1567","severity":2,"message":"1687","line":27378,"column":44,"nodeType":"1565","messageId":"1569","endLine":27378,"endColumn":45,"suggestions":"1695"},{"ruleId":"1567","severity":2,"message":"1687","line":27378,"column":66,"nodeType":"1565","messageId":"1569","endLine":27378,"endColumn":67,"suggestions":"1696"},{"ruleId":"1567","severity":2,"message":"1690","line":27378,"column":77,"nodeType":"1565","messageId":"1569","endLine":27378,"endColumn":78,"suggestions":"1697"},{"ruleId":"1567","severity":2,"message":"1692","line":27378,"column":79,"nodeType":"1565","messageId":"1569","endLine":27378,"endColumn":80,"suggestions":"1698"},{"ruleId":"1567","severity":2,"message":"1687","line":27378,"column":89,"nodeType":"1565","messageId":"1569","endLine":27378,"endColumn":90,"suggestions":"1699"},{"ruleId":"1700","severity":2,"message":"1701","line":27581,"column":8,"nodeType":"1560","messageId":"1702","endLine":27581,"endColumn":41},{"ruleId":"1533","severity":2,"message":"1534","line":27582,"column":11,"nodeType":"1535","messageId":"1536","endLine":27582,"endColumn":13,"suggestions":"1703"},{"ruleId":"1581","severity":1,"message":"1704","line":27788,"column":49,"nodeType":"1525","messageId":"1583","endLine":27788,"endColumn":50},{"ruleId":"1551","severity":2,"message":"1705","line":27891,"column":14,"nodeType":"1553","messageId":"1536","endLine":27891,"endColumn":16},{"ruleId":"1551","severity":2,"message":"1706","line":27976,"column":15,"nodeType":"1553","messageId":"1536","endLine":27976,"endColumn":17},{"ruleId":"1551","severity":2,"message":"1706","line":28006,"column":15,"nodeType":"1553","messageId":"1536","endLine":28006,"endColumn":17},{"ruleId":"1551","severity":2,"message":"1706","line":28170,"column":15,"nodeType":"1553","messageId":"1536","endLine":28170,"endColumn":17},{"ruleId":"1558","severity":2,"message":"1559","line":28400,"column":23,"nodeType":"1560","messageId":"1561","endLine":28400,"endColumn":37},{"ruleId":"1581","severity":1,"message":"1591","line":29012,"column":33,"nodeType":"1525","messageId":"1583","endLine":29012,"endColumn":34},{"ruleId":"1581","severity":1,"message":"1589","line":29204,"column":11,"nodeType":"1525","messageId":"1583","endLine":29204,"endColumn":12},{"ruleId":"1581","severity":1,"message":"1590","line":29205,"column":12,"nodeType":"1525","messageId":"1583","endLine":29205,"endColumn":13},{"ruleId":"1581","severity":1,"message":"1591","line":29206,"column":20,"nodeType":"1525","messageId":"1583","endLine":29206,"endColumn":21},{"ruleId":"1581","severity":1,"message":"1582","line":29207,"column":22,"nodeType":"1525","messageId":"1583","endLine":29207,"endColumn":23},{"ruleId":"1581","severity":1,"message":"1584","line":29208,"column":23,"nodeType":"1525","messageId":"1583","endLine":29208,"endColumn":24},{"ruleId":"1581","severity":1,"message":"1585","line":29209,"column":13,"nodeType":"1525","messageId":"1583","endLine":29209,"endColumn":14},{"ruleId":"1581","severity":1,"message":"1586","line":29210,"column":17,"nodeType":"1525","messageId":"1583","endLine":29210,"endColumn":18},{"ruleId":"1581","severity":1,"message":"1587","line":29211,"column":18,"nodeType":"1525","messageId":"1583","endLine":29211,"endColumn":19},{"ruleId":"1581","severity":1,"message":"1588","line":29212,"column":11,"nodeType":"1525","messageId":"1583","endLine":29212,"endColumn":12},{"ruleId":"1581","severity":1,"message":"1677","line":29213,"column":14,"nodeType":"1525","messageId":"1583","endLine":29213,"endColumn":15},{"ruleId":"1567","severity":2,"message":"1568","line":29266,"column":23,"nodeType":"1565","messageId":"1569","endLine":29266,"endColumn":24,"suggestions":"1707"},{"ruleId":"1581","severity":1,"message":"1708","line":29428,"column":19,"nodeType":"1525","messageId":"1583","endLine":29428,"endColumn":20},{"ruleId":"1558","severity":2,"message":"1559","line":29478,"column":17,"nodeType":"1560","messageId":"1561","endLine":29478,"endColumn":31},{"ruleId":"1581","severity":1,"message":"1681","line":29581,"column":29,"nodeType":"1525","messageId":"1583","endLine":29581,"endColumn":30},{"ruleId":"1558","severity":2,"message":"1559","line":29626,"column":13,"nodeType":"1560","messageId":"1561","endLine":29626,"endColumn":27},{"ruleId":"1551","severity":2,"message":"1706","line":29725,"column":15,"nodeType":"1553","messageId":"1536","endLine":29725,"endColumn":17},{"ruleId":"1551","severity":2,"message":"1706","line":29750,"column":15,"nodeType":"1553","messageId":"1536","endLine":29750,"endColumn":17},{"ruleId":"1709","severity":2,"message":"1710","line":31714,"column":20,"nodeType":"1711","messageId":"1712","endLine":31714,"endColumn":23},{"ruleId":"1581","severity":1,"message":"1590","line":31974,"column":33,"nodeType":"1525","messageId":"1583","endLine":31974,"endColumn":34},{"ruleId":"1581","severity":1,"message":"1591","line":31974,"column":36,"nodeType":"1525","messageId":"1583","endLine":31974,"endColumn":37},{"ruleId":"1581","severity":1,"message":"1590","line":32029,"column":30,"nodeType":"1525","messageId":"1583","endLine":32029,"endColumn":31},{"ruleId":"1551","severity":2,"message":"1713","line":32353,"column":26,"nodeType":"1553","messageId":"1536","endLine":32353,"endColumn":28},{"ruleId":"1581","severity":1,"message":"1584","line":32456,"column":22,"nodeType":"1525","messageId":"1583","endLine":32456,"endColumn":23},{"ruleId":"1581","severity":1,"message":"1584","line":33080,"column":17,"nodeType":"1525","messageId":"1583","endLine":33080,"endColumn":18},{"ruleId":"1581","severity":1,"message":"1589","line":33163,"column":13,"nodeType":"1525","messageId":"1583","endLine":33163,"endColumn":14},{"ruleId":"1551","severity":2,"message":"1621","line":33165,"column":27,"nodeType":"1622","messageId":"1536","endLine":33165,"endColumn":29},{"ruleId":"1581","severity":1,"message":"1714","line":33166,"column":17,"nodeType":"1525","messageId":"1583","endLine":33166,"endColumn":18},{"ruleId":"1581","severity":1,"message":"1715","line":33266,"column":10,"nodeType":"1525","messageId":"1583","endLine":33266,"endColumn":11},{"ruleId":"1551","severity":2,"message":"1621","line":33532,"column":27,"nodeType":"1622","messageId":"1536","endLine":33532,"endColumn":29},{"ruleId":"1551","severity":2,"message":"1621","line":33761,"column":27,"nodeType":"1622","messageId":"1536","endLine":33761,"endColumn":29},{"ruleId":"1581","severity":1,"message":"1590","line":34053,"column":39,"nodeType":"1525","messageId":"1583","endLine":34053,"endColumn":40},{"ruleId":"1581","severity":1,"message":"1584","line":34736,"column":17,"nodeType":"1525","messageId":"1583","endLine":34736,"endColumn":18},{"ruleId":"1558","severity":2,"message":"1559","line":35245,"column":36,"nodeType":"1560","messageId":"1561","endLine":35245,"endColumn":50},{"ruleId":"1558","severity":2,"message":"1559","line":35289,"column":36,"nodeType":"1560","messageId":"1561","endLine":35289,"endColumn":50},{"ruleId":"1558","severity":2,"message":"1559","line":35324,"column":36,"nodeType":"1560","messageId":"1561","endLine":35324,"endColumn":50},{"ruleId":"1558","severity":2,"message":"1559","line":35409,"column":36,"nodeType":"1560","messageId":"1561","endLine":35409,"endColumn":50},{"ruleId":"1551","severity":2,"message":"1716","line":35456,"column":20,"nodeType":"1557","messageId":"1536","endLine":35456,"endColumn":22},{"ruleId":"1558","severity":2,"message":"1559","line":35479,"column":36,"nodeType":"1560","messageId":"1561","endLine":35479,"endColumn":50},{"ruleId":"1558","severity":2,"message":"1559","line":35514,"column":36,"nodeType":"1560","messageId":"1561","endLine":35514,"endColumn":50},{"ruleId":"1551","severity":2,"message":"1716","line":35560,"column":20,"nodeType":"1557","messageId":"1536","endLine":35560,"endColumn":22},{"ruleId":"1581","severity":1,"message":"1585","line":35580,"column":34,"nodeType":"1525","messageId":"1583","endLine":35580,"endColumn":35},{"ruleId":"1581","severity":1,"message":"1585","line":35586,"column":34,"nodeType":"1525","messageId":"1583","endLine":35586,"endColumn":35},{"ruleId":"1717","severity":2,"message":"1718","line":35611,"column":22,"nodeType":"1719","messageId":"1720","endLine":35611,"endColumn":35},{"ruleId":"1551","severity":2,"message":"1716","line":35652,"column":20,"nodeType":"1557","messageId":"1536","endLine":35652,"endColumn":22},{"ruleId":"1664","severity":2,"message":"1721","line":35862,"column":59,"nodeType":"1525","messageId":"1666","endLine":35862,"endColumn":60},{"ruleId":"1558","severity":2,"message":"1559","line":35922,"column":36,"nodeType":"1560","messageId":"1561","endLine":35922,"endColumn":50},{"ruleId":"1717","severity":2,"message":"1718","line":36028,"column":20,"nodeType":"1719","messageId":"1720","endLine":36028,"endColumn":33},{"ruleId":"1558","severity":2,"message":"1559","line":36211,"column":36,"nodeType":"1560","messageId":"1561","endLine":36211,"endColumn":50},{"ruleId":"1551","severity":2,"message":"1716","line":36235,"column":20,"nodeType":"1557","messageId":"1536","endLine":36235,"endColumn":22},{"ruleId":"1551","severity":2,"message":"1716","line":36304,"column":20,"nodeType":"1557","messageId":"1536","endLine":36304,"endColumn":22},{"ruleId":"1664","severity":2,"message":"1722","line":36677,"column":28,"nodeType":"1525","messageId":"1666","endLine":36677,"endColumn":29},{"ruleId":"1558","severity":2,"message":"1559","line":36786,"column":36,"nodeType":"1560","messageId":"1561","endLine":36786,"endColumn":50},{"ruleId":"1558","severity":2,"message":"1559","line":36827,"column":36,"nodeType":"1560","messageId":"1561","endLine":36827,"endColumn":50},{"ruleId":"1664","severity":2,"message":"1723","line":36866,"column":31,"nodeType":"1525","messageId":"1666","endLine":36866,"endColumn":32},{"ruleId":"1664","severity":2,"message":"1723","line":36868,"column":54,"nodeType":"1525","messageId":"1666","endLine":36868,"endColumn":55},{"ruleId":"1664","severity":2,"message":"1724","line":36893,"column":65,"nodeType":"1525","messageId":"1666","endLine":36893,"endColumn":66},{"ruleId":"1664","severity":2,"message":"1725","line":36897,"column":33,"nodeType":"1525","messageId":"1666","endLine":36897,"endColumn":34},{"ruleId":"1664","severity":2,"message":"1722","line":36898,"column":19,"nodeType":"1525","messageId":"1666","endLine":36898,"endColumn":20},{"ruleId":"1664","severity":2,"message":"1724","line":36915,"column":34,"nodeType":"1525","messageId":"1666","endLine":36915,"endColumn":35},{"ruleId":"1664","severity":2,"message":"1724","line":36925,"column":39,"nodeType":"1525","messageId":"1666","endLine":36925,"endColumn":40},{"ruleId":"1664","severity":2,"message":"1725","line":36927,"column":15,"nodeType":"1525","messageId":"1666","endLine":36927,"endColumn":16},{"ruleId":"1558","severity":2,"message":"1559","line":36951,"column":36,"nodeType":"1560","messageId":"1561","endLine":36951,"endColumn":50},{"ruleId":"1664","severity":2,"message":"1726","line":37048,"column":30,"nodeType":"1525","messageId":"1666","endLine":37048,"endColumn":31},{"ruleId":"1581","severity":1,"message":"1590","line":37085,"column":39,"nodeType":"1525","messageId":"1583","endLine":37085,"endColumn":40},{"ruleId":"1581","severity":1,"message":"1591","line":37085,"column":42,"nodeType":"1525","messageId":"1583","endLine":37085,"endColumn":43},{"ruleId":"1581","severity":1,"message":"1582","line":37085,"column":45,"nodeType":"1525","messageId":"1583","endLine":37085,"endColumn":46},{"ruleId":"1581","severity":1,"message":"1584","line":37085,"column":48,"nodeType":"1525","messageId":"1583","endLine":37085,"endColumn":49},{"ruleId":"1558","severity":2,"message":"1559","line":37139,"column":36,"nodeType":"1560","messageId":"1561","endLine":37139,"endColumn":50},{"ruleId":"1558","severity":2,"message":"1559","line":37216,"column":36,"nodeType":"1560","messageId":"1561","endLine":37216,"endColumn":50},{"ruleId":"1717","severity":2,"message":"1718","line":37584,"column":30,"nodeType":"1719","messageId":"1720","endLine":37584,"endColumn":43},{"ruleId":"1631","severity":2,"message":"1632","line":37789,"column":15,"nodeType":"1525","messageId":"1633","endLine":37789,"endColumn":16},{"ruleId":"1581","severity":1,"message":"1584","line":37790,"column":43,"nodeType":"1525","messageId":"1583","endLine":37790,"endColumn":44},{"ruleId":"1631","severity":2,"message":"1632","line":37797,"column":15,"nodeType":"1525","messageId":"1633","endLine":37797,"endColumn":16},{"ruleId":"1597","severity":2,"message":"1598","line":37825,"column":17,"nodeType":"1599","messageId":"1600","endLine":37826,"endColumn":65},{"ruleId":"1709","severity":2,"message":"1710","line":37826,"column":38,"nodeType":"1711","messageId":"1712","endLine":37826,"endColumn":49},{"ruleId":"1631","severity":2,"message":"1632","line":37927,"column":15,"nodeType":"1525","messageId":"1633","endLine":37927,"endColumn":16},{"ruleId":"1631","severity":2,"message":"1632","line":37993,"column":15,"nodeType":"1525","messageId":"1633","endLine":37993,"endColumn":16},{"ruleId":"1631","severity":2,"message":"1632","line":38024,"column":15,"nodeType":"1525","messageId":"1633","endLine":38024,"endColumn":16},{"ruleId":"1551","severity":2,"message":"1716","line":38391,"column":20,"nodeType":"1557","messageId":"1536","endLine":38391,"endColumn":22},{"ruleId":"1664","severity":2,"message":"1727","line":38451,"column":50,"nodeType":"1525","messageId":"1666","endLine":38451,"endColumn":51},{"ruleId":"1631","severity":2,"message":"1632","line":38529,"column":15,"nodeType":"1525","messageId":"1633","endLine":38529,"endColumn":16},{"ruleId":"1558","severity":2,"message":"1559","line":38580,"column":36,"nodeType":"1560","messageId":"1561","endLine":38580,"endColumn":50},{"ruleId":"1558","severity":2,"message":"1559","line":38615,"column":36,"nodeType":"1560","messageId":"1561","endLine":38615,"endColumn":50},{"ruleId":"1664","severity":2,"message":"1723","line":38639,"column":41,"nodeType":"1525","messageId":"1666","endLine":38639,"endColumn":42},{"ruleId":"1558","severity":2,"message":"1559","line":38708,"column":36,"nodeType":"1560","messageId":"1561","endLine":38708,"endColumn":50},{"ruleId":"1558","severity":2,"message":"1559","line":38743,"column":36,"nodeType":"1560","messageId":"1561","endLine":38743,"endColumn":50},{"ruleId":"1664","severity":2,"message":"1724","line":38792,"column":17,"nodeType":"1525","messageId":"1666","endLine":38792,"endColumn":18},{"ruleId":"1551","severity":2,"message":"1716","line":38883,"column":20,"nodeType":"1557","messageId":"1536","endLine":38883,"endColumn":22},{"ruleId":"1664","severity":2,"message":"1728","line":38923,"column":19,"nodeType":"1525","messageId":"1666","endLine":38923,"endColumn":20},{"ruleId":"1664","severity":2,"message":"1723","line":38991,"column":45,"nodeType":"1525","messageId":"1666","endLine":38991,"endColumn":46},{"ruleId":"1664","severity":2,"message":"1723","line":38996,"column":53,"nodeType":"1525","messageId":"1666","endLine":38996,"endColumn":54},{"ruleId":"1664","severity":2,"message":"1722","line":38997,"column":17,"nodeType":"1525","messageId":"1666","endLine":38997,"endColumn":18},{"ruleId":"1664","severity":2,"message":"1724","line":39017,"column":17,"nodeType":"1525","messageId":"1666","endLine":39017,"endColumn":18},{"ruleId":"1664","severity":2,"message":"1724","line":39024,"column":20,"nodeType":"1525","messageId":"1666","endLine":39024,"endColumn":21},{"ruleId":"1551","severity":2,"message":"1716","line":39222,"column":20,"nodeType":"1557","messageId":"1536","endLine":39222,"endColumn":22},{"ruleId":"1551","severity":2,"message":"1716","line":39249,"column":20,"nodeType":"1557","messageId":"1536","endLine":39249,"endColumn":22},{"ruleId":"1558","severity":2,"message":"1559","line":39339,"column":36,"nodeType":"1560","messageId":"1561","endLine":39339,"endColumn":50},{"ruleId":"1664","severity":2,"message":"1729","line":39449,"column":32,"nodeType":"1525","messageId":"1666","endLine":39449,"endColumn":33},{"ruleId":"1664","severity":2,"message":"1729","line":39452,"column":32,"nodeType":"1525","messageId":"1666","endLine":39452,"endColumn":33},{"ruleId":"1664","severity":2,"message":"1729","line":39455,"column":32,"nodeType":"1525","messageId":"1666","endLine":39455,"endColumn":33},{"ruleId":"1551","severity":2,"message":"1716","line":39514,"column":20,"nodeType":"1557","messageId":"1536","endLine":39514,"endColumn":22},{"ruleId":"1664","severity":2,"message":"1730","line":39534,"column":20,"nodeType":"1525","messageId":"1666","endLine":39534,"endColumn":21},{"ruleId":"1664","severity":2,"message":"1724","line":39535,"column":17,"nodeType":"1525","messageId":"1666","endLine":39535,"endColumn":18},{"ruleId":"1664","severity":2,"message":"1723","line":39536,"column":15,"nodeType":"1525","messageId":"1666","endLine":39536,"endColumn":16},{"ruleId":"1558","severity":2,"message":"1559","line":39698,"column":36,"nodeType":"1560","messageId":"1561","endLine":39698,"endColumn":50},{"ruleId":"1664","severity":2,"message":"1725","line":39772,"column":24,"nodeType":"1525","messageId":"1666","endLine":39772,"endColumn":25},{"ruleId":"1551","severity":2,"message":"1716","line":39784,"column":20,"nodeType":"1557","messageId":"1536","endLine":39784,"endColumn":22},{"ruleId":"1581","severity":1,"message":"1586","line":39871,"column":34,"nodeType":"1525","messageId":"1583","endLine":39871,"endColumn":35},{"ruleId":"1581","severity":1,"message":"1587","line":39871,"column":37,"nodeType":"1525","messageId":"1583","endLine":39871,"endColumn":38},{"ruleId":"1664","severity":2,"message":"1724","line":39891,"column":27,"nodeType":"1525","messageId":"1666","endLine":39891,"endColumn":28},{"ruleId":"1664","severity":2,"message":"1721","line":39971,"column":17,"nodeType":"1525","messageId":"1666","endLine":39971,"endColumn":18},{"ruleId":"1551","severity":2,"message":"1716","line":40155,"column":20,"nodeType":"1557","messageId":"1536","endLine":40155,"endColumn":22},{"ruleId":"1664","severity":2,"message":"1724","line":40173,"column":19,"nodeType":"1525","messageId":"1666","endLine":40173,"endColumn":20},{"ruleId":"1581","severity":1,"message":"1585","line":40197,"column":38,"nodeType":"1525","messageId":"1583","endLine":40197,"endColumn":39},{"ruleId":"1581","severity":1,"message":"1586","line":40197,"column":41,"nodeType":"1525","messageId":"1583","endLine":40197,"endColumn":42},{"ruleId":"1551","severity":2,"message":"1562","line":40202,"column":42,"nodeType":"1553","messageId":"1536","endLine":40202,"endColumn":44},{"ruleId":"1558","severity":2,"message":"1559","line":40218,"column":36,"nodeType":"1560","messageId":"1561","endLine":40218,"endColumn":50},{"ruleId":"1551","severity":2,"message":"1716","line":40242,"column":20,"nodeType":"1557","messageId":"1536","endLine":40242,"endColumn":22},{"ruleId":"1551","severity":2,"message":"1562","line":40266,"column":42,"nodeType":"1553","messageId":"1536","endLine":40266,"endColumn":44},{"ruleId":"1533","severity":2,"message":"1534","line":40309,"column":27,"nodeType":"1535","messageId":"1536","endLine":40309,"endColumn":29,"suggestions":"1731"},{"ruleId":"1631","severity":2,"message":"1632","line":40311,"column":17,"nodeType":"1525","messageId":"1633","endLine":40311,"endColumn":18},{"ruleId":"1558","severity":2,"message":"1559","line":40372,"column":36,"nodeType":"1560","messageId":"1561","endLine":40372,"endColumn":50},{"ruleId":"1558","severity":2,"message":"1559","line":40777,"column":36,"nodeType":"1560","messageId":"1561","endLine":40777,"endColumn":50},{"ruleId":"1581","severity":1,"message":"1584","line":40827,"column":50,"nodeType":"1525","messageId":"1583","endLine":40827,"endColumn":51},{"ruleId":"1717","severity":2,"message":"1718","line":40859,"column":24,"nodeType":"1719","messageId":"1720","endLine":40859,"endColumn":37},{"ruleId":"1664","severity":2,"message":"1732","line":40871,"column":19,"nodeType":"1525","messageId":"1666","endLine":40871,"endColumn":20},{"ruleId":"1717","severity":2,"message":"1718","line":40880,"column":22,"nodeType":"1719","messageId":"1720","endLine":40880,"endColumn":35},{"ruleId":"1717","severity":2,"message":"1718","line":40968,"column":24,"nodeType":"1719","messageId":"1720","endLine":40968,"endColumn":37},{"ruleId":"1664","severity":2,"message":"1725","line":40973,"column":19,"nodeType":"1525","messageId":"1666","endLine":40973,"endColumn":20},{"ruleId":"1664","severity":2,"message":"1733","line":40977,"column":24,"nodeType":"1525","messageId":"1666","endLine":40977,"endColumn":25},{"ruleId":"1664","severity":2,"message":"1725","line":40978,"column":21,"nodeType":"1525","messageId":"1666","endLine":40978,"endColumn":22},{"ruleId":"1558","severity":2,"message":"1559","line":41059,"column":36,"nodeType":"1560","messageId":"1561","endLine":41059,"endColumn":50},{"ruleId":"1717","severity":2,"message":"1718","line":41131,"column":22,"nodeType":"1719","messageId":"1720","endLine":41131,"endColumn":35},{"ruleId":"1558","severity":2,"message":"1559","line":41282,"column":36,"nodeType":"1560","messageId":"1561","endLine":41282,"endColumn":50},{"ruleId":"1664","severity":2,"message":"1721","line":41332,"column":20,"nodeType":"1525","messageId":"1666","endLine":41332,"endColumn":21},{"ruleId":"1664","severity":2,"message":"1730","line":41333,"column":17,"nodeType":"1525","messageId":"1666","endLine":41333,"endColumn":18},{"ruleId":"1717","severity":2,"message":"1718","line":41476,"column":24,"nodeType":"1719","messageId":"1720","endLine":41476,"endColumn":37},{"ruleId":"1664","severity":2,"message":"1727","line":41491,"column":20,"nodeType":"1525","messageId":"1666","endLine":41491,"endColumn":21},{"ruleId":"1717","severity":2,"message":"1718","line":41607,"column":24,"nodeType":"1719","messageId":"1720","endLine":41607,"endColumn":37},{"ruleId":"1551","severity":2,"message":"1716","line":41626,"column":20,"nodeType":"1557","messageId":"1536","endLine":41626,"endColumn":22},{"ruleId":"1558","severity":2,"message":"1559","line":41660,"column":36,"nodeType":"1560","messageId":"1561","endLine":41660,"endColumn":50},{"ruleId":"1533","severity":2,"message":"1534","line":41733,"column":19,"nodeType":"1535","messageId":"1536","endLine":41733,"endColumn":21,"suggestions":"1734"},{"ruleId":"1664","severity":2,"message":"1721","line":41762,"column":20,"nodeType":"1525","messageId":"1666","endLine":41762,"endColumn":21},{"ruleId":"1664","severity":2,"message":"1730","line":41763,"column":17,"nodeType":"1525","messageId":"1666","endLine":41763,"endColumn":18},{"ruleId":"1558","severity":2,"message":"1559","line":41793,"column":36,"nodeType":"1560","messageId":"1561","endLine":41793,"endColumn":50},{"ruleId":"1717","severity":2,"message":"1718","line":41865,"column":24,"nodeType":"1719","messageId":"1720","endLine":41865,"endColumn":37},{"ruleId":"1664","severity":2,"message":"1735","line":41879,"column":20,"nodeType":"1525","messageId":"1666","endLine":41879,"endColumn":21},{"ruleId":"1664","severity":2,"message":"1733","line":41880,"column":17,"nodeType":"1525","messageId":"1666","endLine":41880,"endColumn":18},{"ruleId":"1664","severity":2,"message":"1736","line":41888,"column":21,"nodeType":"1525","messageId":"1666","endLine":41888,"endColumn":22},{"ruleId":"1717","severity":2,"message":"1718","line":41897,"column":24,"nodeType":"1719","messageId":"1720","endLine":41897,"endColumn":37},{"ruleId":"1558","severity":2,"message":"1559","line":41928,"column":36,"nodeType":"1560","messageId":"1561","endLine":41928,"endColumn":50},{"ruleId":"1717","severity":2,"message":"1718","line":41996,"column":24,"nodeType":"1719","messageId":"1720","endLine":41996,"endColumn":37},{"ruleId":"1664","severity":2,"message":"1722","line":42008,"column":20,"nodeType":"1525","messageId":"1666","endLine":42008,"endColumn":21},{"ruleId":"1664","severity":2,"message":"1735","line":42009,"column":17,"nodeType":"1525","messageId":"1666","endLine":42009,"endColumn":18},{"ruleId":"1664","severity":2,"message":"1737","line":42017,"column":21,"nodeType":"1525","messageId":"1666","endLine":42017,"endColumn":22},{"ruleId":"1717","severity":2,"message":"1718","line":42026,"column":24,"nodeType":"1719","messageId":"1720","endLine":42026,"endColumn":37},{"ruleId":"1558","severity":2,"message":"1559","line":42050,"column":36,"nodeType":"1560","messageId":"1561","endLine":42050,"endColumn":50},{"ruleId":"1581","severity":1,"message":"1582","line":42076,"column":44,"nodeType":"1525","messageId":"1583","endLine":42076,"endColumn":45},{"ruleId":"1558","severity":2,"message":"1559","line":42120,"column":36,"nodeType":"1560","messageId":"1561","endLine":42120,"endColumn":50},{"ruleId":"1717","severity":2,"message":"1718","line":42192,"column":24,"nodeType":"1719","messageId":"1720","endLine":42192,"endColumn":37},{"ruleId":"1558","severity":2,"message":"1559","line":42273,"column":36,"nodeType":"1560","messageId":"1561","endLine":42273,"endColumn":50},{"ruleId":"1533","severity":2,"message":"1534","line":42359,"column":23,"nodeType":"1535","messageId":"1536","endLine":42359,"endColumn":25,"suggestions":"1738"},{"ruleId":"1717","severity":2,"message":"1718","line":42367,"column":22,"nodeType":"1719","messageId":"1720","endLine":42367,"endColumn":35},{"ruleId":"1717","severity":2,"message":"1718","line":42389,"column":22,"nodeType":"1719","messageId":"1720","endLine":42389,"endColumn":35},{"ruleId":"1558","severity":2,"message":"1559","line":42408,"column":36,"nodeType":"1560","messageId":"1561","endLine":42408,"endColumn":50},{"ruleId":"1717","severity":2,"message":"1718","line":42522,"column":24,"nodeType":"1719","messageId":"1720","endLine":42522,"endColumn":37},{"ruleId":"1551","severity":2,"message":"1716","line":42615,"column":20,"nodeType":"1557","messageId":"1536","endLine":42615,"endColumn":22},{"ruleId":"1717","severity":2,"message":"1718","line":42632,"column":22,"nodeType":"1719","messageId":"1720","endLine":42632,"endColumn":35},{"ruleId":"1551","severity":2,"message":"1716","line":42668,"column":20,"nodeType":"1557","messageId":"1536","endLine":42668,"endColumn":22},{"ruleId":"1664","severity":2,"message":"1723","line":42684,"column":20,"nodeType":"1525","messageId":"1666","endLine":42684,"endColumn":21},{"ruleId":"1664","severity":2,"message":"1725","line":42692,"column":57,"nodeType":"1525","messageId":"1666","endLine":42692,"endColumn":58},{"ruleId":"1558","severity":2,"message":"1559","line":42739,"column":36,"nodeType":"1560","messageId":"1561","endLine":42739,"endColumn":50},{"ruleId":"1558","severity":2,"message":"1559","line":42784,"column":36,"nodeType":"1560","messageId":"1561","endLine":42784,"endColumn":50},{"ruleId":"1639","severity":2,"message":"1739","line":42806,"column":56,"nodeType":"1740","messageId":"1641","endLine":42806,"endColumn":72},{"ruleId":"1558","severity":2,"message":"1559","line":42837,"column":36,"nodeType":"1560","messageId":"1561","endLine":42837,"endColumn":50},{"ruleId":"1551","severity":2,"message":"1716","line":42904,"column":20,"nodeType":"1557","messageId":"1536","endLine":42904,"endColumn":22},{"ruleId":"1717","severity":2,"message":"1718","line":42929,"column":22,"nodeType":"1719","messageId":"1720","endLine":42929,"endColumn":35},{"ruleId":"1664","severity":2,"message":"1735","line":42940,"column":19,"nodeType":"1525","messageId":"1666","endLine":42940,"endColumn":20},{"ruleId":"1717","severity":2,"message":"1718","line":42952,"column":22,"nodeType":"1719","messageId":"1720","endLine":42952,"endColumn":35},{"ruleId":"1664","severity":2,"message":"1735","line":42961,"column":19,"nodeType":"1525","messageId":"1666","endLine":42961,"endColumn":20},{"ruleId":"1717","severity":2,"message":"1718","line":42973,"column":22,"nodeType":"1719","messageId":"1720","endLine":42973,"endColumn":35},{"ruleId":"1664","severity":2,"message":"1735","line":42984,"column":19,"nodeType":"1525","messageId":"1666","endLine":42984,"endColumn":20},{"ruleId":"1717","severity":2,"message":"1718","line":42996,"column":22,"nodeType":"1719","messageId":"1720","endLine":42996,"endColumn":35},{"ruleId":"1544","severity":2,"message":"1545","line":43173,"column":20,"nodeType":"1741","messageId":"1536","endLine":43173,"endColumn":22},{"ruleId":"1664","severity":2,"message":"1742","line":43254,"column":19,"nodeType":"1525","messageId":"1666","endLine":43254,"endColumn":20},{"ruleId":"1558","severity":2,"message":"1559","line":43478,"column":36,"nodeType":"1560","messageId":"1561","endLine":43478,"endColumn":50},{"ruleId":"1558","severity":2,"message":"1559","line":43540,"column":36,"nodeType":"1560","messageId":"1561","endLine":43540,"endColumn":50},{"ruleId":"1558","severity":2,"message":"1559","line":43592,"column":36,"nodeType":"1560","messageId":"1561","endLine":43592,"endColumn":50},{"ruleId":"1558","severity":2,"message":"1559","line":43634,"column":36,"nodeType":"1560","messageId":"1561","endLine":43634,"endColumn":50},{"ruleId":"1558","severity":2,"message":"1559","line":43678,"column":36,"nodeType":"1560","messageId":"1561","endLine":43678,"endColumn":50},{"ruleId":"1558","severity":2,"message":"1559","line":43734,"column":36,"nodeType":"1560","messageId":"1561","endLine":43734,"endColumn":50},{"ruleId":"1581","severity":1,"message":"1582","line":43756,"column":51,"nodeType":"1525","messageId":"1583","endLine":43756,"endColumn":52},{"ruleId":"1558","severity":2,"message":"1559","line":43777,"column":36,"nodeType":"1560","messageId":"1561","endLine":43777,"endColumn":50},{"ruleId":"1558","severity":2,"message":"1559","line":43820,"column":36,"nodeType":"1560","messageId":"1561","endLine":43820,"endColumn":50},{"ruleId":"1558","severity":2,"message":"1559","line":43875,"column":36,"nodeType":"1560","messageId":"1561","endLine":43875,"endColumn":50},{"ruleId":"1558","severity":2,"message":"1559","line":43941,"column":36,"nodeType":"1560","messageId":"1561","endLine":43941,"endColumn":50},{"ruleId":"1581","severity":1,"message":"1585","line":44146,"column":38,"nodeType":"1525","messageId":"1583","endLine":44146,"endColumn":39},{"ruleId":"1558","severity":2,"message":"1559","line":44175,"column":36,"nodeType":"1560","messageId":"1561","endLine":44175,"endColumn":50},{"ruleId":"1581","severity":1,"message":"1584","line":44223,"column":50,"nodeType":"1525","messageId":"1583","endLine":44223,"endColumn":51},{"ruleId":"1533","severity":2,"message":"1534","line":44227,"column":19,"nodeType":"1535","messageId":"1536","endLine":44227,"endColumn":21,"suggestions":"1743"},{"ruleId":"1717","severity":2,"message":"1718","line":44288,"column":24,"nodeType":"1719","messageId":"1720","endLine":44288,"endColumn":37},{"ruleId":"1717","severity":2,"message":"1718","line":44330,"column":22,"nodeType":"1719","messageId":"1720","endLine":44330,"endColumn":35},{"ruleId":"1717","severity":2,"message":"1718","line":44383,"column":32,"nodeType":"1719","messageId":"1720","endLine":44383,"endColumn":45},{"ruleId":"1581","severity":1,"message":"1744","line":44386,"column":27,"nodeType":"1525","messageId":"1583","endLine":44386,"endColumn":28},{"ruleId":"1717","severity":2,"message":"1718","line":44394,"column":28,"nodeType":"1719","messageId":"1720","endLine":44394,"endColumn":41},{"ruleId":"1717","severity":2,"message":"1718","line":44405,"column":22,"nodeType":"1719","messageId":"1720","endLine":44405,"endColumn":35},{"ruleId":"1717","severity":2,"message":"1718","line":44441,"column":30,"nodeType":"1719","messageId":"1720","endLine":44441,"endColumn":43},{"ruleId":"1717","severity":2,"message":"1718","line":44455,"column":26,"nodeType":"1719","messageId":"1720","endLine":44455,"endColumn":39},{"ruleId":"1717","severity":2,"message":"1718","line":44466,"column":22,"nodeType":"1719","messageId":"1720","endLine":44466,"endColumn":35},{"ruleId":"1664","severity":2,"message":"1723","line":44621,"column":15,"nodeType":"1525","messageId":"1666","endLine":44621,"endColumn":16},{"ruleId":"1664","severity":2,"message":"1723","line":44642,"column":15,"nodeType":"1525","messageId":"1666","endLine":44642,"endColumn":16},{"ruleId":"1664","severity":2,"message":"1723","line":44652,"column":27,"nodeType":"1525","messageId":"1666","endLine":44652,"endColumn":28},{"ruleId":"1664","severity":2,"message":"1745","line":44654,"column":19,"nodeType":"1525","messageId":"1666","endLine":44654,"endColumn":20},{"ruleId":"1558","severity":2,"message":"1559","line":44852,"column":36,"nodeType":"1560","messageId":"1561","endLine":44852,"endColumn":50},{"ruleId":"1558","severity":2,"message":"1559","line":44899,"column":36,"nodeType":"1560","messageId":"1561","endLine":44899,"endColumn":50},{"ruleId":"1717","severity":2,"message":"1718","line":44976,"column":28,"nodeType":"1719","messageId":"1720","endLine":44976,"endColumn":41},{"ruleId":"1717","severity":2,"message":"1718","line":44986,"column":22,"nodeType":"1719","messageId":"1720","endLine":44986,"endColumn":35},{"ruleId":"1717","severity":2,"message":"1718","line":45009,"column":24,"nodeType":"1719","messageId":"1720","endLine":45009,"endColumn":37},{"ruleId":"1664","severity":2,"message":"1724","line":45030,"column":27,"nodeType":"1525","messageId":"1666","endLine":45030,"endColumn":28},{"ruleId":"1664","severity":2,"message":"1724","line":45096,"column":15,"nodeType":"1525","messageId":"1666","endLine":45096,"endColumn":16},{"ruleId":"1664","severity":2,"message":"1724","line":45107,"column":34,"nodeType":"1525","messageId":"1666","endLine":45107,"endColumn":35},{"ruleId":"1664","severity":2,"message":"1724","line":45109,"column":34,"nodeType":"1525","messageId":"1666","endLine":45109,"endColumn":35},{"ruleId":"1664","severity":2,"message":"1745","line":45124,"column":17,"nodeType":"1525","messageId":"1666","endLine":45124,"endColumn":18},{"ruleId":"1664","severity":2,"message":"1746","line":45125,"column":15,"nodeType":"1525","messageId":"1666","endLine":45125,"endColumn":16},{"ruleId":"1664","severity":2,"message":"1747","line":45126,"column":15,"nodeType":"1525","messageId":"1666","endLine":45126,"endColumn":16},{"ruleId":"1664","severity":2,"message":"1748","line":45127,"column":15,"nodeType":"1525","messageId":"1666","endLine":45127,"endColumn":16},{"ruleId":"1664","severity":2,"message":"1749","line":45128,"column":15,"nodeType":"1525","messageId":"1666","endLine":45128,"endColumn":16},{"ruleId":"1664","severity":2,"message":"1750","line":45130,"column":15,"nodeType":"1525","messageId":"1666","endLine":45130,"endColumn":16},{"ruleId":"1558","severity":2,"message":"1559","line":45258,"column":36,"nodeType":"1560","messageId":"1561","endLine":45258,"endColumn":50},{"ruleId":"1533","severity":2,"message":"1534","line":45312,"column":21,"nodeType":"1535","messageId":"1536","endLine":45312,"endColumn":23,"suggestions":"1751"},{"ruleId":"1558","severity":2,"message":"1559","line":45335,"column":36,"nodeType":"1560","messageId":"1561","endLine":45335,"endColumn":50},{"ruleId":"1717","severity":2,"message":"1718","line":45431,"column":20,"nodeType":"1719","messageId":"1720","endLine":45431,"endColumn":33},{"ruleId":"1717","severity":2,"message":"1718","line":45472,"column":22,"nodeType":"1719","messageId":"1720","endLine":45472,"endColumn":35},{"ruleId":"1717","severity":2,"message":"1718","line":45793,"column":22,"nodeType":"1719","messageId":"1720","endLine":45793,"endColumn":35},{"ruleId":"1664","severity":2,"message":"1722","line":45800,"column":24,"nodeType":"1525","messageId":"1666","endLine":45800,"endColumn":25},{"ruleId":"1717","severity":2,"message":"1718","line":45811,"column":22,"nodeType":"1719","messageId":"1720","endLine":45811,"endColumn":35},{"ruleId":"1664","severity":2,"message":"1736","line":45819,"column":15,"nodeType":"1525","messageId":"1666","endLine":45819,"endColumn":16},{"ruleId":"1664","severity":2,"message":"1745","line":45825,"column":65,"nodeType":"1525","messageId":"1666","endLine":45825,"endColumn":66},{"ruleId":"1664","severity":2,"message":"1736","line":45830,"column":47,"nodeType":"1525","messageId":"1666","endLine":45830,"endColumn":48},{"ruleId":"1664","severity":2,"message":"1745","line":45831,"column":22,"nodeType":"1525","messageId":"1666","endLine":45831,"endColumn":23},{"ruleId":"1664","severity":2,"message":"1723","line":45878,"column":19,"nodeType":"1525","messageId":"1666","endLine":45878,"endColumn":20},{"ruleId":"1664","severity":2,"message":"1728","line":45879,"column":17,"nodeType":"1525","messageId":"1666","endLine":45879,"endColumn":18},{"ruleId":"1551","severity":2,"message":"1716","line":45902,"column":20,"nodeType":"1557","messageId":"1536","endLine":45902,"endColumn":22},{"ruleId":"1664","severity":2,"message":"1728","line":46021,"column":25,"nodeType":"1525","messageId":"1666","endLine":46021,"endColumn":26},{"ruleId":"1664","severity":2,"message":"1728","line":46081,"column":25,"nodeType":"1525","messageId":"1666","endLine":46081,"endColumn":26},{"ruleId":"1664","severity":2,"message":"1728","line":46101,"column":25,"nodeType":"1525","messageId":"1666","endLine":46101,"endColumn":26},{"ruleId":"1717","severity":2,"message":"1718","line":46397,"column":22,"nodeType":"1719","messageId":"1720","endLine":46397,"endColumn":35},{"ruleId":"1551","severity":2,"message":"1562","line":46649,"column":42,"nodeType":"1553","messageId":"1536","endLine":46649,"endColumn":44},{"ruleId":"1558","severity":2,"message":"1559","line":46693,"column":36,"nodeType":"1560","messageId":"1561","endLine":46693,"endColumn":50},{"ruleId":"1717","severity":2,"message":"1718","line":46837,"column":22,"nodeType":"1719","messageId":"1720","endLine":46837,"endColumn":35},{"ruleId":"1717","severity":2,"message":"1718","line":46943,"column":22,"nodeType":"1719","messageId":"1720","endLine":46943,"endColumn":35},{"ruleId":"1717","severity":2,"message":"1718","line":47012,"column":20,"nodeType":"1719","messageId":"1720","endLine":47012,"endColumn":33},{"ruleId":"1581","severity":1,"message":"1591","line":47440,"column":50,"nodeType":"1525","messageId":"1583","endLine":47440,"endColumn":51},{"ruleId":"1664","severity":2,"message":"1665","line":47503,"column":67,"nodeType":"1525","messageId":"1666","endLine":47503,"endColumn":68},{"ruleId":"1664","severity":2,"message":"1742","line":47508,"column":20,"nodeType":"1525","messageId":"1666","endLine":47508,"endColumn":21},{"ruleId":"1664","severity":2,"message":"1730","line":47528,"column":20,"nodeType":"1525","messageId":"1666","endLine":47528,"endColumn":21},{"ruleId":"1664","severity":2,"message":"1721","line":47529,"column":22,"nodeType":"1525","messageId":"1666","endLine":47529,"endColumn":23},{"ruleId":"1717","severity":2,"message":"1718","line":47635,"column":22,"nodeType":"1719","messageId":"1720","endLine":47635,"endColumn":35},{"ruleId":"1664","severity":2,"message":"1735","line":47642,"column":24,"nodeType":"1525","messageId":"1666","endLine":47642,"endColumn":25},{"ruleId":"1717","severity":2,"message":"1718","line":47653,"column":22,"nodeType":"1719","messageId":"1720","endLine":47653,"endColumn":35},{"ruleId":"1664","severity":2,"message":"1732","line":47662,"column":63,"nodeType":"1525","messageId":"1666","endLine":47662,"endColumn":64},{"ruleId":"1664","severity":2,"message":"1747","line":47664,"column":20,"nodeType":"1525","messageId":"1666","endLine":47664,"endColumn":21},{"ruleId":"1664","severity":2,"message":"1732","line":47665,"column":47,"nodeType":"1525","messageId":"1666","endLine":47665,"endColumn":48},{"ruleId":"1664","severity":2,"message":"1747","line":47666,"column":22,"nodeType":"1525","messageId":"1666","endLine":47666,"endColumn":23},{"ruleId":"1551","severity":2,"message":"1716","line":47777,"column":20,"nodeType":"1557","messageId":"1536","endLine":47777,"endColumn":22},{"ruleId":"1717","severity":2,"message":"1718","line":48047,"column":22,"nodeType":"1719","messageId":"1720","endLine":48047,"endColumn":35},{"ruleId":"1664","severity":2,"message":"1733","line":48054,"column":19,"nodeType":"1525","messageId":"1666","endLine":48054,"endColumn":20},{"ruleId":"1717","severity":2,"message":"1718","line":48066,"column":22,"nodeType":"1719","messageId":"1720","endLine":48066,"endColumn":35},{"ruleId":"1558","severity":2,"message":"1559","line":48095,"column":36,"nodeType":"1560","messageId":"1561","endLine":48095,"endColumn":50},{"ruleId":"1664","severity":2,"message":"1722","line":48201,"column":19,"nodeType":"1525","messageId":"1666","endLine":48201,"endColumn":20},{"ruleId":"1717","severity":2,"message":"1718","line":48259,"column":24,"nodeType":"1719","messageId":"1720","endLine":48259,"endColumn":37},{"ruleId":"1558","severity":2,"message":"1559","line":48285,"column":36,"nodeType":"1560","messageId":"1561","endLine":48285,"endColumn":50},{"ruleId":"1664","severity":2,"message":"1735","line":48442,"column":19,"nodeType":"1525","messageId":"1666","endLine":48442,"endColumn":20},{"ruleId":"1717","severity":2,"message":"1718","line":48632,"column":22,"nodeType":"1719","messageId":"1720","endLine":48632,"endColumn":35},{"ruleId":"1717","severity":2,"message":"1718","line":48661,"column":22,"nodeType":"1719","messageId":"1720","endLine":48661,"endColumn":35},{"ruleId":"1664","severity":2,"message":"1752","line":48673,"column":19,"nodeType":"1525","messageId":"1666","endLine":48673,"endColumn":20},{"ruleId":"1717","severity":2,"message":"1718","line":48682,"column":22,"nodeType":"1719","messageId":"1720","endLine":48682,"endColumn":35},{"ruleId":"1717","severity":2,"message":"1718","line":48715,"column":24,"nodeType":"1719","messageId":"1720","endLine":48715,"endColumn":37},{"ruleId":"1664","severity":2,"message":"1723","line":48736,"column":17,"nodeType":"1525","messageId":"1666","endLine":48736,"endColumn":18},{"ruleId":"1717","severity":2,"message":"1718","line":48748,"column":24,"nodeType":"1719","messageId":"1720","endLine":48748,"endColumn":37},{"ruleId":"1551","severity":2,"message":"1562","line":49016,"column":42,"nodeType":"1553","messageId":"1536","endLine":49016,"endColumn":44},{"ruleId":"1551","severity":2,"message":"1716","line":49095,"column":20,"nodeType":"1557","messageId":"1536","endLine":49095,"endColumn":22},{"ruleId":"1551","severity":2,"message":"1562","line":49097,"column":49,"nodeType":"1553","messageId":"1536","endLine":49097,"endColumn":51},{"ruleId":"1717","severity":2,"message":"1718","line":49117,"column":22,"nodeType":"1719","messageId":"1720","endLine":49117,"endColumn":35},{"ruleId":"1551","severity":2,"message":"1716","line":49722,"column":20,"nodeType":"1557","messageId":"1536","endLine":49722,"endColumn":22},{"ruleId":"1717","severity":2,"message":"1718","line":49758,"column":26,"nodeType":"1719","messageId":"1720","endLine":49758,"endColumn":39},{"ruleId":"1664","severity":2,"message":"1725","line":49818,"column":17,"nodeType":"1525","messageId":"1666","endLine":49818,"endColumn":18},{"ruleId":"1664","severity":2,"message":"1752","line":49825,"column":19,"nodeType":"1525","messageId":"1666","endLine":49825,"endColumn":20},{"ruleId":"1717","severity":2,"message":"1718","line":49975,"column":24,"nodeType":"1719","messageId":"1720","endLine":49975,"endColumn":37},{"ruleId":"1551","severity":2,"message":"1716","line":50081,"column":20,"nodeType":"1557","messageId":"1536","endLine":50081,"endColumn":22},{"ruleId":"1558","severity":2,"message":"1559","line":50128,"column":36,"nodeType":"1560","messageId":"1561","endLine":50128,"endColumn":50},{"ruleId":"1664","severity":2,"message":"1730","line":50153,"column":18,"nodeType":"1525","messageId":"1666","endLine":50153,"endColumn":19},{"ruleId":"1717","severity":2,"message":"1718","line":50235,"column":24,"nodeType":"1719","messageId":"1720","endLine":50235,"endColumn":37},{"ruleId":"1664","severity":2,"message":"1728","line":50249,"column":15,"nodeType":"1525","messageId":"1666","endLine":50249,"endColumn":16},{"ruleId":"1664","severity":2,"message":"1730","line":50311,"column":15,"nodeType":"1525","messageId":"1666","endLine":50311,"endColumn":16},{"ruleId":"1717","severity":2,"message":"1718","line":50585,"column":22,"nodeType":"1719","messageId":"1720","endLine":50585,"endColumn":35},{"ruleId":"1717","severity":2,"message":"1718","line":50632,"column":20,"nodeType":"1719","messageId":"1720","endLine":50632,"endColumn":33},{"ruleId":"1717","severity":2,"message":"1718","line":50682,"column":22,"nodeType":"1719","messageId":"1720","endLine":50682,"endColumn":35},{"ruleId":"1558","severity":2,"message":"1559","line":50705,"column":36,"nodeType":"1560","messageId":"1561","endLine":50705,"endColumn":50},{"ruleId":"1717","severity":2,"message":"1718","line":50765,"column":22,"nodeType":"1719","messageId":"1720","endLine":50765,"endColumn":35},{"ruleId":"1717","severity":2,"message":"1718","line":50828,"column":22,"nodeType":"1719","messageId":"1720","endLine":50828,"endColumn":35},{"ruleId":"1717","severity":2,"message":"1718","line":50892,"column":22,"nodeType":"1719","messageId":"1720","endLine":50892,"endColumn":35},{"ruleId":"1717","severity":2,"message":"1718","line":51134,"column":24,"nodeType":"1719","messageId":"1720","endLine":51134,"endColumn":37},{"ruleId":"1551","severity":2,"message":"1716","line":51241,"column":20,"nodeType":"1557","messageId":"1536","endLine":51241,"endColumn":22},{"ruleId":"1581","severity":1,"message":"1590","line":51312,"column":75,"nodeType":"1525","messageId":"1583","endLine":51312,"endColumn":76},{"ruleId":"1551","severity":2,"message":"1716","line":51396,"column":20,"nodeType":"1557","messageId":"1536","endLine":51396,"endColumn":22},{"ruleId":"1558","severity":2,"message":"1559","line":51416,"column":36,"nodeType":"1560","messageId":"1561","endLine":51416,"endColumn":50},{"ruleId":"1551","severity":2,"message":"1716","line":51440,"column":20,"nodeType":"1557","messageId":"1536","endLine":51440,"endColumn":22},{"ruleId":"1551","severity":2,"message":"1562","line":51452,"column":42,"nodeType":"1553","messageId":"1536","endLine":51452,"endColumn":44},{"ruleId":"1551","severity":2,"message":"1562","line":51453,"column":42,"nodeType":"1553","messageId":"1536","endLine":51453,"endColumn":44},{"ruleId":"1558","severity":2,"message":"1559","line":51469,"column":36,"nodeType":"1560","messageId":"1561","endLine":51469,"endColumn":50},{"ruleId":"1558","severity":2,"message":"1559","line":51504,"column":36,"nodeType":"1560","messageId":"1561","endLine":51504,"endColumn":50},{"ruleId":"1581","severity":1,"message":"1591","line":51575,"column":50,"nodeType":"1525","messageId":"1583","endLine":51575,"endColumn":51},{"ruleId":"1581","severity":1,"message":"1591","line":51578,"column":50,"nodeType":"1525","messageId":"1583","endLine":51578,"endColumn":51},{"ruleId":"1551","severity":2,"message":"1562","line":51581,"column":42,"nodeType":"1553","messageId":"1536","endLine":51581,"endColumn":44},{"ruleId":"1551","severity":2,"message":"1716","line":51615,"column":20,"nodeType":"1557","messageId":"1536","endLine":51615,"endColumn":22},{"ruleId":"1664","severity":2,"message":"1722","line":51946,"column":28,"nodeType":"1525","messageId":"1666","endLine":51946,"endColumn":29},{"ruleId":"1551","severity":2,"message":"1716","line":52045,"column":20,"nodeType":"1557","messageId":"1536","endLine":52045,"endColumn":22},{"ruleId":"1717","severity":2,"message":"1718","line":52130,"column":22,"nodeType":"1719","messageId":"1720","endLine":52130,"endColumn":35},{"ruleId":"1664","severity":2,"message":"1725","line":52135,"column":24,"nodeType":"1525","messageId":"1666","endLine":52135,"endColumn":25},{"ruleId":"1664","severity":2,"message":"1725","line":52139,"column":20,"nodeType":"1525","messageId":"1666","endLine":52139,"endColumn":21},{"ruleId":"1717","severity":2,"message":"1718","line":52157,"column":22,"nodeType":"1719","messageId":"1720","endLine":52157,"endColumn":35},{"ruleId":"1664","severity":2,"message":"1723","line":52246,"column":22,"nodeType":"1525","messageId":"1666","endLine":52246,"endColumn":23},{"ruleId":"1717","severity":2,"message":"1718","line":52299,"column":28,"nodeType":"1719","messageId":"1720","endLine":52299,"endColumn":41},{"ruleId":"1717","severity":2,"message":"1718","line":52310,"column":22,"nodeType":"1719","messageId":"1720","endLine":52310,"endColumn":35},{"ruleId":"1717","severity":2,"message":"1718","line":52364,"column":24,"nodeType":"1719","messageId":"1720","endLine":52364,"endColumn":37},{"ruleId":"1551","severity":2,"message":"1716","line":52507,"column":20,"nodeType":"1557","messageId":"1536","endLine":52507,"endColumn":22},{"ruleId":"1717","severity":2,"message":"1718","line":52558,"column":22,"nodeType":"1719","messageId":"1720","endLine":52558,"endColumn":35},{"ruleId":"1551","severity":2,"message":"1562","line":52607,"column":42,"nodeType":"1553","messageId":"1536","endLine":52607,"endColumn":44},{"ruleId":"1558","severity":2,"message":"1559","line":52623,"column":36,"nodeType":"1560","messageId":"1561","endLine":52623,"endColumn":50},{"ruleId":"1551","severity":2,"message":"1716","line":52667,"column":20,"nodeType":"1557","messageId":"1536","endLine":52667,"endColumn":22},{"ruleId":"1717","severity":2,"message":"1718","line":52734,"column":24,"nodeType":"1719","messageId":"1720","endLine":52734,"endColumn":37},{"ruleId":"1717","severity":2,"message":"1718","line":52761,"column":22,"nodeType":"1719","messageId":"1720","endLine":52761,"endColumn":35},{"ruleId":"1558","severity":2,"message":"1559","line":52781,"column":36,"nodeType":"1560","messageId":"1561","endLine":52781,"endColumn":50},{"ruleId":"1631","severity":2,"message":"1632","line":52801,"column":13,"nodeType":"1525","messageId":"1633","endLine":52801,"endColumn":14},{"ruleId":"1558","severity":2,"message":"1559","line":52824,"column":36,"nodeType":"1560","messageId":"1561","endLine":52824,"endColumn":50},{"ruleId":"1558","severity":2,"message":"1559","line":52859,"column":34,"nodeType":"1560","messageId":"1561","endLine":52859,"endColumn":48},{"ruleId":"1551","severity":2,"message":"1716","line":52944,"column":20,"nodeType":"1557","messageId":"1536","endLine":52944,"endColumn":22},{"ruleId":"1717","severity":2,"message":"1718","line":53150,"column":22,"nodeType":"1719","messageId":"1720","endLine":53150,"endColumn":35},{"ruleId":"1558","severity":2,"message":"1559","line":53272,"column":36,"nodeType":"1560","messageId":"1561","endLine":53272,"endColumn":50},{"ruleId":"1551","severity":2,"message":"1716","line":53296,"column":20,"nodeType":"1557","messageId":"1536","endLine":53296,"endColumn":22},{"ruleId":"1664","severity":2,"message":"1725","line":53327,"column":19,"nodeType":"1525","messageId":"1666","endLine":53327,"endColumn":20},{"ruleId":"1664","severity":2,"message":"1722","line":53328,"column":17,"nodeType":"1525","messageId":"1666","endLine":53328,"endColumn":18},{"ruleId":"1551","severity":2,"message":"1716","line":53585,"column":18,"nodeType":"1557","messageId":"1536","endLine":53585,"endColumn":20},{"ruleId":"1664","severity":2,"message":"1727","line":53715,"column":29,"nodeType":"1525","messageId":"1666","endLine":53715,"endColumn":30},{"ruleId":"1664","severity":2,"message":"1727","line":53716,"column":46,"nodeType":"1525","messageId":"1666","endLine":53716,"endColumn":47},{"ruleId":"1664","severity":2,"message":"1735","line":53754,"column":32,"nodeType":"1525","messageId":"1666","endLine":53754,"endColumn":33},{"ruleId":"1664","severity":2,"message":"1736","line":53762,"column":17,"nodeType":"1525","messageId":"1666","endLine":53762,"endColumn":18},{"ruleId":"1717","severity":2,"message":"1718","line":53771,"column":22,"nodeType":"1719","messageId":"1720","endLine":53771,"endColumn":35},{"ruleId":"1664","severity":2,"message":"1735","line":53774,"column":18,"nodeType":"1525","messageId":"1666","endLine":53774,"endColumn":19},{"ruleId":"1664","severity":2,"message":"1753","line":53781,"column":19,"nodeType":"1525","messageId":"1666","endLine":53781,"endColumn":20},{"ruleId":"1664","severity":2,"message":"1732","line":53782,"column":17,"nodeType":"1525","messageId":"1666","endLine":53782,"endColumn":18},{"ruleId":"1717","severity":2,"message":"1718","line":53791,"column":22,"nodeType":"1719","messageId":"1720","endLine":53791,"endColumn":35},{"ruleId":"1664","severity":2,"message":"1721","line":53808,"column":41,"nodeType":"1525","messageId":"1666","endLine":53808,"endColumn":42},{"ruleId":"1664","severity":2,"message":"1730","line":53852,"column":17,"nodeType":"1525","messageId":"1666","endLine":53852,"endColumn":18},{"ruleId":"1558","severity":2,"message":"1559","line":53930,"column":34,"nodeType":"1560","messageId":"1561","endLine":53930,"endColumn":48},{"ruleId":"1558","severity":2,"message":"1559","line":54055,"column":34,"nodeType":"1560","messageId":"1561","endLine":54055,"endColumn":48},{"ruleId":"1558","severity":2,"message":"1559","line":54156,"column":34,"nodeType":"1560","messageId":"1561","endLine":54156,"endColumn":48},{"ruleId":"1551","severity":2,"message":"1716","line":54183,"column":18,"nodeType":"1557","messageId":"1536","endLine":54183,"endColumn":20},{"ruleId":"1551","severity":2,"message":"1716","line":54187,"column":20,"nodeType":"1557","messageId":"1536","endLine":54187,"endColumn":22},{"ruleId":"1551","severity":2,"message":"1716","line":54223,"column":20,"nodeType":"1557","messageId":"1536","endLine":54223,"endColumn":22},{"ruleId":"1558","severity":2,"message":"1559","line":54257,"column":36,"nodeType":"1560","messageId":"1561","endLine":54257,"endColumn":50},{"ruleId":"1581","severity":1,"message":"1582","line":54280,"column":46,"nodeType":"1525","messageId":"1583","endLine":54280,"endColumn":47},{"ruleId":"1558","severity":2,"message":"1559","line":54316,"column":36,"nodeType":"1560","messageId":"1561","endLine":54316,"endColumn":50},{"ruleId":"1717","severity":2,"message":"1718","line":54448,"column":16,"nodeType":"1719","messageId":"1720","endLine":54448,"endColumn":29},{"ruleId":"1717","severity":2,"message":"1718","line":54587,"column":22,"nodeType":"1719","messageId":"1720","endLine":54587,"endColumn":35},{"ruleId":"1664","severity":2,"message":"1730","line":54626,"column":61,"nodeType":"1525","messageId":"1666","endLine":54626,"endColumn":62},{"ruleId":"1664","severity":2,"message":"1730","line":54633,"column":61,"nodeType":"1525","messageId":"1666","endLine":54633,"endColumn":62},{"ruleId":"1664","severity":2,"message":"1722","line":54710,"column":9,"nodeType":"1525","messageId":"1666","endLine":54710,"endColumn":10},{"ruleId":"1717","severity":2,"message":"1718","line":54795,"column":22,"nodeType":"1719","messageId":"1720","endLine":54795,"endColumn":35},{"ruleId":"1717","severity":2,"message":"1718","line":54844,"column":22,"nodeType":"1719","messageId":"1720","endLine":54844,"endColumn":35},{"ruleId":"1717","severity":2,"message":"1718","line":54897,"column":26,"nodeType":"1719","messageId":"1720","endLine":54897,"endColumn":39},{"ruleId":"1717","severity":2,"message":"1718","line":54908,"column":22,"nodeType":"1719","messageId":"1720","endLine":54908,"endColumn":35},{"ruleId":"1551","severity":2,"message":"1716","line":54937,"column":18,"nodeType":"1557","messageId":"1536","endLine":54937,"endColumn":20},{"ruleId":"1664","severity":2,"message":"1722","line":54977,"column":19,"nodeType":"1525","messageId":"1666","endLine":54977,"endColumn":20},{"ruleId":"1664","severity":2,"message":"1735","line":54990,"column":20,"nodeType":"1525","messageId":"1666","endLine":54990,"endColumn":21},{"ruleId":"1664","severity":2,"message":"1735","line":54994,"column":73,"nodeType":"1525","messageId":"1666","endLine":54994,"endColumn":74},{"ruleId":"1664","severity":2,"message":"1735","line":55002,"column":33,"nodeType":"1525","messageId":"1666","endLine":55002,"endColumn":34},{"ruleId":"1664","severity":2,"message":"1735","line":55019,"column":17,"nodeType":"1525","messageId":"1666","endLine":55019,"endColumn":18},{"ruleId":"1664","severity":2,"message":"1747","line":55019,"column":24,"nodeType":"1525","messageId":"1666","endLine":55019,"endColumn":25},{"ruleId":"1664","severity":2,"message":"1749","line":55023,"column":22,"nodeType":"1525","messageId":"1666","endLine":55023,"endColumn":23},{"ruleId":"1664","severity":2,"message":"1730","line":55074,"column":20,"nodeType":"1525","messageId":"1666","endLine":55074,"endColumn":21},{"ruleId":"1664","severity":2,"message":"1724","line":55075,"column":17,"nodeType":"1525","messageId":"1666","endLine":55075,"endColumn":18},{"ruleId":"1717","severity":2,"message":"1718","line":55104,"column":20,"nodeType":"1719","messageId":"1720","endLine":55104,"endColumn":33},{"ruleId":"1664","severity":2,"message":"1665","line":55502,"column":24,"nodeType":"1525","messageId":"1666","endLine":55502,"endColumn":25},{"ruleId":"1551","severity":2,"message":"1562","line":55521,"column":38,"nodeType":"1553","messageId":"1536","endLine":55521,"endColumn":40},{"ruleId":"1551","severity":2,"message":"1562","line":55523,"column":38,"nodeType":"1553","messageId":"1536","endLine":55523,"endColumn":40},{"ruleId":"1597","severity":2,"message":"1598","line":55571,"column":17,"nodeType":"1599","messageId":"1600","endLine":55577,"endColumn":20},{"ruleId":"1551","severity":2,"message":"1754","line":55675,"column":30,"nodeType":"1622","messageId":"1536","endLine":55675,"endColumn":32},{"ruleId":"1523","severity":2,"message":"1532","line":2,"column":35,"nodeType":"1525","messageId":"1526","endLine":2,"endColumn":36},{"ruleId":"1533","severity":2,"message":"1534","line":3,"column":9,"nodeType":"1535","messageId":"1536","endLine":3,"endColumn":11,"suggestions":"1755"},{"ruleId":"1523","severity":2,"message":"1532","line":61,"column":33,"nodeType":"1525","messageId":"1526","endLine":61,"endColumn":34},{"ruleId":"1533","severity":2,"message":"1534","line":62,"column":9,"nodeType":"1535","messageId":"1536","endLine":62,"endColumn":11,"suggestions":"1756"},{"ruleId":"1631","severity":2,"message":"1632","line":64,"column":7,"nodeType":"1525","messageId":"1633","endLine":64,"endColumn":8},{"ruleId":"1551","severity":2,"message":"1757","line":83,"column":14,"nodeType":"1557","messageId":"1536","endLine":83,"endColumn":16},{"ruleId":"1631","severity":2,"message":"1632","line":184,"column":13,"nodeType":"1525","messageId":"1633","endLine":184,"endColumn":14},{"ruleId":"1551","severity":2,"message":"1562","line":222,"column":41,"nodeType":"1553","messageId":"1536","endLine":222,"endColumn":43},{"ruleId":"1631","severity":2,"message":"1632","line":267,"column":13,"nodeType":"1525","messageId":"1633","endLine":267,"endColumn":14},{"ruleId":"1523","severity":2,"message":"1524","line":11,"column":25,"nodeType":"1525","messageId":"1526","endLine":11,"endColumn":38},{"ruleId":"1523","severity":2,"message":"1527","line":30,"column":1,"nodeType":"1525","messageId":"1526","endLine":30,"endColumn":7},{"ruleId":"1523","severity":2,"message":"1527","line":1,"column":1,"nodeType":"1525","messageId":"1526","endLine":1,"endColumn":7},{"ruleId":"1523","severity":2,"message":"1532","line":4,"column":35,"nodeType":"1525","messageId":"1526","endLine":4,"endColumn":36},{"ruleId":"1533","severity":2,"message":"1534","line":5,"column":15,"nodeType":"1535","messageId":"1536","endLine":5,"endColumn":17,"suggestions":"1758"},{"ruleId":"1523","severity":2,"message":"1532","line":16,"column":38,"nodeType":"1525","messageId":"1526","endLine":16,"endColumn":39},{"ruleId":"1533","severity":2,"message":"1534","line":17,"column":15,"nodeType":"1535","messageId":"1536","endLine":17,"endColumn":17,"suggestions":"1759"},{"ruleId":"1523","severity":2,"message":"1539","line":175,"column":52,"nodeType":"1525","messageId":"1526","endLine":175,"endColumn":64},{"ruleId":"1523","severity":2,"message":"1532","line":186,"column":41,"nodeType":"1525","messageId":"1526","endLine":186,"endColumn":42},{"ruleId":"1533","severity":2,"message":"1534","line":187,"column":15,"nodeType":"1535","messageId":"1536","endLine":187,"endColumn":17,"suggestions":"1760"},{"ruleId":"1523","severity":2,"message":"1532","line":288,"column":41,"nodeType":"1525","messageId":"1526","endLine":288,"endColumn":42},{"ruleId":"1533","severity":2,"message":"1534","line":289,"column":15,"nodeType":"1535","messageId":"1536","endLine":289,"endColumn":17,"suggestions":"1761"},{"ruleId":"1523","severity":2,"message":"1543","line":311,"column":22,"nodeType":"1525","messageId":"1526","endLine":311,"endColumn":32},{"ruleId":"1523","severity":2,"message":"1543","line":498,"column":20,"nodeType":"1525","messageId":"1526","endLine":498,"endColumn":30},{"ruleId":"1533","severity":2,"message":"1534","line":526,"column":19,"nodeType":"1535","messageId":"1536","endLine":526,"endColumn":21,"suggestions":"1762"},{"ruleId":"1581","severity":1,"message":"1590","line":801,"column":23,"nodeType":"1525","messageId":"1583","endLine":801,"endColumn":24},{"ruleId":"1551","severity":2,"message":"1621","line":801,"column":29,"nodeType":"1622","messageId":"1536","endLine":801,"endColumn":31},{"ruleId":"1700","severity":2,"message":"1701","line":2,"column":22,"nodeType":"1560","messageId":"1702","endLine":2,"endColumn":57},{"ruleId":"1700","severity":2,"message":"1701","line":4,"column":16,"nodeType":"1560","messageId":"1702","endLine":4,"endColumn":45},{"ruleId":"1581","severity":1,"message":"1763","line":37,"column":19,"nodeType":"1525","messageId":"1583","endLine":37,"endColumn":24},"no-undef","'importScripts' is not defined.","Identifier","undef","'define' is not defined.","@typescript-eslint/ban-ts-comment","Do not use \"@ts-ignore\" because it alters compilation errors.","Line","tsDirectiveComment","'_' is not defined.","no-empty","Empty block statement.","BlockStatement","unexpected",["1764"],["1765"],"'registration' is not defined.",["1766"],["1767"],"'ExtendableEvent' is not defined.","'FetchEvent' is not defined.","no-constant-condition","Unexpected constant condition.","BinaryExpression",["1768"],["1769"],["1770"],["1771"],"@typescript-eslint/no-empty-function","Unexpected empty method 'enqueueForceUpdate'.","FunctionExpression","Unexpected empty method 'enqueueReplaceState'.","Unexpected empty method 'enqueueSetState'.","Unexpected empty function 'i6'.","FunctionDeclaration","no-prototype-builtins","Do not access Object.prototype method 'hasOwnProperty' from target object.","CallExpression","prototypeBuildIn","Unexpected empty function.","no-misleading-character-class","Unexpected combined character in character class.","Literal","combiningClass","no-useless-escape","Unnecessary escape character: \\-.","unnecessaryEscape",["1772","1773"],"no-cond-assign","Expected a conditional expression and instead saw an assignment.","AssignmentExpression","missing",["1774"],"'MSApp' is not defined.","Unexpected empty function 'R6'.","getter-return","Expected to return a value in method 'get'.","expected","@typescript-eslint/no-unused-vars","'r' is defined but never used.","unusedVar","'i' is defined but never used.","'a' is defined but never used.","'o' is defined but never used.","'s' is defined but never used.","'l' is defined but never used.","'e' is defined but never used.","'t' is defined but never used.","'n' is defined but never used.",["1775"],"valid-typeof","Invalid typeof comparison value.","invalidValue","Unexpected empty method 'persist'.","no-fallthrough","Expected a 'break' statement before 'case'.","SwitchCase","case","no-control-regex","Unexpected control character(s) in regular expression: \\x00.","Unexpected empty function 'Kc'.","Unexpected empty function '_5'.","Unexpected empty function 'Kp'.",["1776"],["1777"],"Unexpected empty method 'useMutableSource'.",["1778"],["1779"],"Unexpected empty function 'Xg'.","no-func-assign","'A6' is a function.","isAFunction","'R6' is a function.","'__REACT_DEVTOOLS_GLOBAL_HOOK__' is not defined.",["1780"],"'Te' is a function.",["1781"],"'d1' is a function.","Unexpected empty arrow function.","ArrowFunctionExpression","'Il' is a function.",["1782"],"'__SENTRY_DEBUG__' is not defined.",["1783"],["1784"],["1785"],["1786"],["1787"],"@typescript-eslint/no-this-alias","Unexpected aliasing of 'this' to local variable.","thisAssignment",["1788"],["1789"],["1790"],"'__SENTRY_BROWSER_BUNDLE__' is not defined.",["1791"],"no-self-assign","'t' is assigned to itself.","selfAssignment","'__SENTRY_TRACING__' is not defined.",["1792"],["1793"],["1794"],["1795"],["1796"],["1797"],["1798"],["1799"],["1800"],["1801"],"'n' is assigned to itself.","'r' is assigned to itself.","'__SENTRY_RELEASE__' is not defined.",["1802"],"Unexpected control character(s) in regular expression: \\x0c.","no-case-declarations","Unexpected lexical declaration in case block.","VariableDeclaration",["1803"],["1804"],["1805"],"no-redeclare","'r' is already defined.","redeclared","'y' is assigned a value but never used.",["1806"],["1807"],["1808"],["1809"],["1810"],["1811"],["1812"],["1813"],["1814"],"'u' is defined but never used.",["1815"],"'t' is assigned a value but never used.","'n' is assigned a value but never used.","'f' is assigned a value but never used.",["1816"],"'m' is defined but never used.","'x' is defined but never used.","Unexpected empty function 'JO'.","Unexpected empty method 'idle'.","Unnecessary escape character: \\..",["1817","1818"],["1819","1820"],"Unnecessary escape character: \\,.",["1821","1822"],"Unnecessary escape character: \\/.",["1823","1824"],["1825","1826"],["1827","1828"],["1829","1830"],["1831","1832"],["1833","1834"],["1835","1836"],"@typescript-eslint/no-var-requires","Require statement not part of import statement.","noVarReqs",["1837"],"'x' is assigned a value but never used.","Unexpected empty method 'update'.","Unexpected empty method 'unmount'.",["1838","1839"],"'i' is assigned a value but never used.","no-sparse-arrays","Unexpected comma in middle of array.","ArrayExpression","unexpectedSparseArray","Unexpected empty method 'componentDidUpdate'.","'r' is assigned a value but never used.","'c' is assigned a value but never used.","Unexpected empty function 'e'.","no-unsafe-finally","Unsafe usage of ThrowStatement.","ThrowStatement","unsafeUsage","'a' is already defined.","'d' is already defined.","'l' is already defined.","'s' is already defined.","'f' is already defined.","'_' is already defined.","'i' is already defined.","'u' is already defined.","'C' is already defined.","'o' is already defined.",["1840"],"'g' is already defined.","'p' is already defined.",["1841"],"'h' is already defined.","'m' is already defined.","'x' is already defined.",["1842"],"'a.remainingValue' is assigned to itself.","MemberExpression","UnaryExpression","'n' is already defined.",["1843"],"'h' is assigned a value but never used.","'b' is already defined.","'I' is already defined.","'N' is already defined.","'V' is already defined.","'j' is already defined.","'H' is already defined.",["1844"],"'c' is already defined.","'T' is already defined.","Unexpected empty method 'onError'.",["1845"],["1846"],"Unexpected empty function 'L'.",["1847"],["1848"],["1849"],["1850"],["1851"],"'theme' is defined but never used.",{"messageId":"1852","data":"1853","fix":"1854","desc":"1855"},{"messageId":"1852","data":"1856","fix":"1857","desc":"1855"},{"messageId":"1852","data":"1858","fix":"1859","desc":"1855"},{"messageId":"1852","data":"1860","fix":"1861","desc":"1855"},{"messageId":"1852","data":"1862","fix":"1863","desc":"1855"},{"messageId":"1852","data":"1864","fix":"1865","desc":"1855"},{"messageId":"1852","data":"1866","fix":"1867","desc":"1855"},{"messageId":"1852","data":"1868","fix":"1869","desc":"1855"},{"messageId":"1870","fix":"1871","desc":"1872"},{"messageId":"1873","fix":"1874","desc":"1875"},{"messageId":"1852","data":"1876","fix":"1877","desc":"1855"},{"messageId":"1852","data":"1878","fix":"1879","desc":"1855"},{"messageId":"1852","data":"1880","fix":"1881","desc":"1855"},{"messageId":"1852","data":"1882","fix":"1883","desc":"1855"},{"messageId":"1852","data":"1884","fix":"1885","desc":"1855"},{"messageId":"1852","data":"1886","fix":"1887","desc":"1855"},{"messageId":"1852","data":"1888","fix":"1889","desc":"1855"},{"messageId":"1852","data":"1890","fix":"1891","desc":"1855"},{"messageId":"1852","data":"1892","fix":"1893","desc":"1855"},{"messageId":"1852","data":"1894","fix":"1895","desc":"1855"},{"messageId":"1852","data":"1896","fix":"1897","desc":"1855"},{"messageId":"1852","data":"1898","fix":"1899","desc":"1855"},{"messageId":"1852","data":"1900","fix":"1901","desc":"1855"},{"messageId":"1852","data":"1902","fix":"1903","desc":"1855"},{"messageId":"1852","data":"1904","fix":"1905","desc":"1855"},{"messageId":"1852","data":"1906","fix":"1907","desc":"1855"},{"messageId":"1852","data":"1908","fix":"1909","desc":"1855"},{"messageId":"1852","data":"1910","fix":"1911","desc":"1855"},{"messageId":"1852","data":"1912","fix":"1913","desc":"1855"},{"messageId":"1852","data":"1914","fix":"1915","desc":"1855"},{"messageId":"1852","data":"1916","fix":"1917","desc":"1855"},{"messageId":"1852","data":"1918","fix":"1919","desc":"1855"},{"messageId":"1852","data":"1920","fix":"1921","desc":"1855"},{"messageId":"1852","data":"1922","fix":"1923","desc":"1855"},{"messageId":"1852","data":"1924","fix":"1925","desc":"1855"},{"messageId":"1852","data":"1926","fix":"1927","desc":"1855"},{"messageId":"1852","data":"1928","fix":"1929","desc":"1855"},{"messageId":"1852","data":"1930","fix":"1931","desc":"1855"},{"messageId":"1852","data":"1932","fix":"1933","desc":"1855"},{"messageId":"1852","data":"1934","fix":"1935","desc":"1855"},{"messageId":"1852","data":"1936","fix":"1937","desc":"1855"},{"messageId":"1852","data":"1938","fix":"1939","desc":"1855"},{"messageId":"1852","data":"1940","fix":"1941","desc":"1855"},{"messageId":"1852","data":"1942","fix":"1943","desc":"1855"},{"messageId":"1852","data":"1944","fix":"1945","desc":"1855"},{"messageId":"1852","data":"1946","fix":"1947","desc":"1855"},{"messageId":"1852","data":"1948","fix":"1949","desc":"1855"},{"messageId":"1852","data":"1950","fix":"1951","desc":"1855"},{"messageId":"1852","data":"1952","fix":"1953","desc":"1855"},{"messageId":"1852","data":"1954","fix":"1955","desc":"1855"},{"messageId":"1852","data":"1956","fix":"1957","desc":"1855"},{"messageId":"1852","data":"1958","fix":"1959","desc":"1855"},{"messageId":"1852","data":"1960","fix":"1961","desc":"1855"},{"messageId":"1870","fix":"1962","desc":"1872"},{"messageId":"1873","fix":"1963","desc":"1875"},{"messageId":"1870","fix":"1964","desc":"1872"},{"messageId":"1873","fix":"1965","desc":"1875"},{"messageId":"1870","fix":"1966","desc":"1872"},{"messageId":"1873","fix":"1967","desc":"1875"},{"messageId":"1870","fix":"1968","desc":"1872"},{"messageId":"1873","fix":"1969","desc":"1875"},{"messageId":"1870","fix":"1970","desc":"1872"},{"messageId":"1873","fix":"1971","desc":"1875"},{"messageId":"1870","fix":"1972","desc":"1872"},{"messageId":"1873","fix":"1973","desc":"1875"},{"messageId":"1870","fix":"1974","desc":"1872"},{"messageId":"1873","fix":"1975","desc":"1875"},{"messageId":"1870","fix":"1976","desc":"1872"},{"messageId":"1873","fix":"1977","desc":"1875"},{"messageId":"1870","fix":"1978","desc":"1872"},{"messageId":"1873","fix":"1979","desc":"1875"},{"messageId":"1870","fix":"1980","desc":"1872"},{"messageId":"1873","fix":"1981","desc":"1875"},{"messageId":"1852","data":"1982","fix":"1983","desc":"1855"},{"messageId":"1870","fix":"1984","desc":"1872"},{"messageId":"1873","fix":"1985","desc":"1875"},{"messageId":"1852","data":"1986","fix":"1987","desc":"1855"},{"messageId":"1852","data":"1988","fix":"1989","desc":"1855"},{"messageId":"1852","data":"1990","fix":"1991","desc":"1855"},{"messageId":"1852","data":"1992","fix":"1993","desc":"1855"},{"messageId":"1852","data":"1994","fix":"1995","desc":"1855"},{"messageId":"1852","data":"1996","fix":"1997","desc":"1855"},{"messageId":"1852","data":"1998","fix":"1999","desc":"1855"},{"messageId":"1852","data":"2000","fix":"2001","desc":"1855"},{"messageId":"1852","data":"2002","fix":"2003","desc":"1855"},{"messageId":"1852","data":"2004","fix":"2005","desc":"1855"},{"messageId":"1852","data":"2006","fix":"2007","desc":"1855"},{"messageId":"1852","data":"2008","fix":"2009","desc":"1855"},"suggestComment",{"type":"2010"},{"range":"2011","text":"2012"},"Add comment inside empty block statement.",{"type":"2010"},{"range":"2013","text":"2012"},{"type":"2010"},{"range":"2014","text":"2012"},{"type":"2010"},{"range":"2015","text":"2012"},{"type":"2010"},{"range":"2016","text":"2012"},{"type":"2010"},{"range":"2017","text":"2012"},{"type":"2010"},{"range":"2018","text":"2012"},{"type":"2010"},{"range":"2019","text":"2012"},"removeEscape",{"range":"2020","text":"2021"},"Remove the `\\`. This maintains the current functionality.","escapeBackslash",{"range":"2022","text":"2023"},"Replace the `\\` with `\\\\` to include the actual backslash character.",{"type":"2010"},{"range":"2024","text":"2012"},{"type":"2010"},{"range":"2025","text":"2012"},{"type":"2010"},{"range":"2026","text":"2012"},{"type":"2010"},{"range":"2027","text":"2012"},{"type":"2010"},{"range":"2028","text":"2012"},{"type":"2010"},{"range":"2029","text":"2012"},{"type":"2010"},{"range":"2030","text":"2012"},{"type":"2010"},{"range":"2031","text":"2012"},{"type":"2010"},{"range":"2032","text":"2012"},{"type":"2010"},{"range":"2033","text":"2012"},{"type":"2010"},{"range":"2034","text":"2012"},{"type":"2010"},{"range":"2035","text":"2012"},{"type":"2010"},{"range":"2036","text":"2012"},{"type":"2010"},{"range":"2037","text":"2012"},{"type":"2010"},{"range":"2038","text":"2012"},{"type":"2010"},{"range":"2039","text":"2012"},{"type":"2010"},{"range":"2040","text":"2012"},{"type":"2010"},{"range":"2041","text":"2012"},{"type":"2010"},{"range":"2042","text":"2012"},{"type":"2010"},{"range":"2043","text":"2012"},{"type":"2010"},{"range":"2044","text":"2012"},{"type":"2010"},{"range":"2045","text":"2012"},{"type":"2010"},{"range":"2046","text":"2012"},{"type":"2010"},{"range":"2047","text":"2012"},{"type":"2010"},{"range":"2048","text":"2012"},{"type":"2010"},{"range":"2049","text":"2012"},{"type":"2010"},{"range":"2050","text":"2012"},{"type":"2010"},{"range":"2051","text":"2012"},{"type":"2010"},{"range":"2052","text":"2012"},{"type":"2010"},{"range":"2053","text":"2012"},{"type":"2010"},{"range":"2054","text":"2012"},{"type":"2010"},{"range":"2055","text":"2012"},{"type":"2010"},{"range":"2056","text":"2012"},{"type":"2010"},{"range":"2057","text":"2012"},{"type":"2010"},{"range":"2058","text":"2012"},{"type":"2010"},{"range":"2059","text":"2012"},{"type":"2010"},{"range":"2060","text":"2012"},{"type":"2010"},{"range":"2061","text":"2012"},{"type":"2010"},{"range":"2062","text":"2012"},{"type":"2010"},{"range":"2063","text":"2012"},{"type":"2010"},{"range":"2064","text":"2012"},{"type":"2010"},{"range":"2065","text":"2012"},{"type":"2010"},{"range":"2066","text":"2012"},{"range":"2067","text":"2021"},{"range":"2068","text":"2023"},{"range":"2069","text":"2021"},{"range":"2070","text":"2023"},{"range":"2071","text":"2021"},{"range":"2072","text":"2023"},{"range":"2073","text":"2021"},{"range":"2074","text":"2023"},{"range":"2075","text":"2021"},{"range":"2076","text":"2023"},{"range":"2077","text":"2021"},{"range":"2078","text":"2023"},{"range":"2079","text":"2021"},{"range":"2080","text":"2023"},{"range":"2081","text":"2021"},{"range":"2082","text":"2023"},{"range":"2083","text":"2021"},{"range":"2084","text":"2023"},{"range":"2085","text":"2021"},{"range":"2086","text":"2023"},{"type":"2010"},{"range":"2087","text":"2012"},{"range":"2088","text":"2021"},{"range":"2089","text":"2023"},{"type":"2010"},{"range":"2090","text":"2012"},{"type":"2010"},{"range":"2091","text":"2012"},{"type":"2010"},{"range":"2092","text":"2012"},{"type":"2010"},{"range":"2093","text":"2012"},{"type":"2010"},{"range":"2094","text":"2012"},{"type":"2010"},{"range":"2095","text":"2012"},{"type":"2010"},{"range":"2096","text":"2012"},{"type":"2010"},{"range":"2097","text":"2012"},{"type":"2010"},{"range":"2098","text":"2012"},{"type":"2010"},{"range":"2099","text":"2012"},{"type":"2010"},{"range":"2100","text":"2012"},{"type":"2010"},{"range":"2101","text":"2012"},"block",[136,136]," /* empty */ ",[18043,18043],[46614,46614],[60762,60762],[136,136],[18043,18043],[46614,46614],[60762,60762],[25358,25359],"",[25358,25358],"\\",[32792,32792],[49591,49591],[135381,135390],[135401,135410],[189392,189392],[224899,224899],[248078,248078],[252702,252702],[327191,327191],[337052,337052],[345080,345080],[346579,346579],[347098,347098],[347398,347398],[348823,348823],[349571,349571],[352181,352181],[353580,353580],[409795,409795],[423558,423558],[426916,426916],[427286,427286],[428583,428583],[428829,428829],[430006,430006],[444368,444368],[449539,449539],[450166,450166],[458550,458550],[501393,501393],[501652,501652],[516409,516409],[541542,541542],[594059,594059],[594550,594550],[608216,608216],[615208,615208],[616809,616809],[624639,624639],[625554,625554],[650280,650280],[665385,665385],[729402,729402],[875093,875094],[875093,875093],[875115,875116],[875115,875115],[875126,875127],[875126,875126],[875128,875129],[875128,875128],[875138,875139],[875138,875138],[875204,875205],[875204,875204],[875226,875227],[875226,875226],[875237,875238],[875237,875237],[875239,875240],[875239,875239],[875249,875250],[875249,875249],[879967,879967],[924167,924168],[924167,924167],[1267353,1267353],[1314689,1314689],[1333660,1333660],[1390172,1390172],[1425646,1425646],[53,53],[1727,1727],[111,111],[404,404],[5333,5333],[8077,8077],[14993,14993]] \ No newline at end of file diff --git a/.gitignore b/.gitignore index b318cc6b..5e2bcb7e 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,7 @@ dev-dist/ # misc .DS_Store +.env .env.local .env.development.local .env.test.local @@ -27,6 +28,6 @@ yarn-error.log* .nyc-output/ .turbo/ +.eslintcache -/.env /postgres-data diff --git a/.prettierignore b/.prettierignore index 277ef98c..4f72ea01 100644 --- a/.prettierignore +++ b/.prettierignore @@ -2,3 +2,4 @@ dev-dist/ dist/ pnpm-lock.yaml pnpm-workspace.yaml +migrations/ diff --git a/Makefile b/Makefile index bda2c030..34bf7016 100644 --- a/Makefile +++ b/Makefile @@ -4,10 +4,18 @@ reset-db: $(MAKE) drop-db $(MAKE) create-db -drop-db: +drop-db: drop-db-dev drop-db-test + +drop-db-dev: $(PG_CONTAINER) dropdb --if-exists -h 127.0.0.1 -p 5432 -U postgres peated + +drop-db-test: $(PG_CONTAINER) dropdb --if-exists -h 127.0.0.1 -p 5432 -U postgres test_peated -create-db: +create-db: create-db-dev create-db-test + +create-db-dev: $(PG_CONTAINER) createdb -E utf-8 -h 127.0.0.1 -p 5432 -U postgres peated || exit 0 + +create-db-test: $(PG_CONTAINER) createdb -E utf-8 -h 127.0.0.1 -p 5432 -U postgres test_peated || exit 0 diff --git a/apps/api/migrations/0003_military_preak.sql b/apps/api/migrations/0003_military_preak.sql new file mode 100644 index 00000000..d5a9fe65 --- /dev/null +++ b/apps/api/migrations/0003_military_preak.sql @@ -0,0 +1,26 @@ +DO $$ BEGIN + CREATE TYPE "follow_status" AS ENUM('none', 'pending', 'following'); +EXCEPTION + WHEN duplicate_object THEN null; +END $$; + +CREATE TABLE IF NOT EXISTS "follow" ( + "from_user_id" bigint NOT NULL, + "to_user_id" bigint NOT NULL, + "status" follow_status DEFAULT 'pending' NOT NULL, + "created_at" timestamp DEFAULT now() NOT NULL +); +--> statement-breakpoint +ALTER TABLE "follow" ADD CONSTRAINT "follow_from_user_id_to_user_id" PRIMARY KEY("from_user_id","to_user_id"); + +DO $$ BEGIN + ALTER TABLE "follow" ADD CONSTRAINT "follow_from_user_id_user_id_fk" FOREIGN KEY ("from_user_id") REFERENCES "user"("id") ON DELETE no action ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; + +DO $$ BEGIN + ALTER TABLE "follow" ADD CONSTRAINT "follow_to_user_id_user_id_fk" FOREIGN KEY ("to_user_id") REFERENCES "user"("id") ON DELETE no action ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; diff --git a/apps/api/migrations/meta/0003_snapshot.json b/apps/api/migrations/meta/0003_snapshot.json new file mode 100644 index 00000000..88ea3288 --- /dev/null +++ b/apps/api/migrations/meta/0003_snapshot.json @@ -0,0 +1,736 @@ +{ + "version": "5", + "dialect": "pg", + "id": "85857c02-ada6-4b92-9055-b6db2c133ca0", + "prevId": "97bd7919-1dac-4d82-b4e0-4fe6df99bf24", + "tables": { + "bottle": { + "name": "bottle", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "category": { + "name": "category", + "type": "category", + "primaryKey": false, + "notNull": false + }, + "brand_id": { + "name": "brand_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "stated_age": { + "name": "stated_age", + "type": "smallint", + "primaryKey": false, + "notNull": false + }, + "total_tastings": { + "name": "total_tastings", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "created_by_id": { + "name": "created_by_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "bottle_brand_unq": { + "name": "bottle_brand_unq", + "columns": [ + "name", + "brand_id" + ], + "isUnique": true + } + }, + "foreignKeys": { + "bottle_brand_id_entity_id_fk": { + "name": "bottle_brand_id_entity_id_fk", + "tableFrom": "bottle", + "tableTo": "entity", + "columnsFrom": [ + "brand_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "bottle_created_by_id_user_id_fk": { + "name": "bottle_created_by_id_user_id_fk", + "tableFrom": "bottle", + "tableTo": "user", + "columnsFrom": [ + "created_by_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {} + }, + "bottle_distiller": { + "name": "bottle_distiller", + "schema": "", + "columns": { + "bottle_id": { + "name": "bottle_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "distiller_id": { + "name": "distiller_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "bottle_distiller_bottle_id_bottle_id_fk": { + "name": "bottle_distiller_bottle_id_bottle_id_fk", + "tableFrom": "bottle_distiller", + "tableTo": "bottle", + "columnsFrom": [ + "bottle_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "bottle_distiller_distiller_id_entity_id_fk": { + "name": "bottle_distiller_distiller_id_entity_id_fk", + "tableFrom": "bottle_distiller", + "tableTo": "entity", + "columnsFrom": [ + "distiller_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "bottle_distiller_bottle_id_distiller_id": { + "name": "bottle_distiller_bottle_id_distiller_id", + "columns": [ + "bottle_id", + "distiller_id" + ] + } + } + }, + "change": { + "name": "change", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "object_id": { + "name": "object_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "object_type": { + "name": "object_type", + "type": "object_type", + "primaryKey": false, + "notNull": true + }, + "data": { + "name": "data", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "created_by_id": { + "name": "created_by_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "change_created_by_id_user_id_fk": { + "name": "change_created_by_id_user_id_fk", + "tableFrom": "change", + "tableTo": "user", + "columnsFrom": [ + "created_by_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {} + }, + "edition": { + "name": "edition", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "barrel": { + "name": "barrel", + "type": "smallint", + "primaryKey": false, + "notNull": false + }, + "bottle_id": { + "name": "bottle_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "created_by_id": { + "name": "created_by_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "edition_unq": { + "name": "edition_unq", + "columns": [ + "bottle_id", + "name", + "barrel" + ], + "isUnique": true + } + }, + "foreignKeys": { + "edition_bottle_id_bottle_id_fk": { + "name": "edition_bottle_id_bottle_id_fk", + "tableFrom": "edition", + "tableTo": "bottle", + "columnsFrom": [ + "bottle_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "edition_created_by_id_user_id_fk": { + "name": "edition_created_by_id_user_id_fk", + "tableFrom": "edition", + "tableTo": "user", + "columnsFrom": [ + "created_by_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {} + }, + "entity": { + "name": "entity", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "country": { + "name": "country", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "region": { + "name": "region", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "entity_type[]", + "primaryKey": false, + "notNull": true + }, + "total_bottles": { + "name": "total_bottles", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_tastings": { + "name": "total_tastings", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "created_by_id": { + "name": "created_by_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "entity_name_unq": { + "name": "entity_name_unq", + "columns": [ + "name" + ], + "isUnique": true + } + }, + "foreignKeys": { + "entity_created_by_id_user_id_fk": { + "name": "entity_created_by_id_user_id_fk", + "tableFrom": "entity", + "tableTo": "user", + "columnsFrom": [ + "created_by_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {} + }, + "follow": { + "name": "follow", + "schema": "", + "columns": { + "from_user_id": { + "name": "from_user_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "to_user_id": { + "name": "to_user_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "follow_status", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "follow_from_user_id_user_id_fk": { + "name": "follow_from_user_id_user_id_fk", + "tableFrom": "follow", + "tableTo": "user", + "columnsFrom": [ + "from_user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "follow_to_user_id_user_id_fk": { + "name": "follow_to_user_id_user_id_fk", + "tableFrom": "follow", + "tableTo": "user", + "columnsFrom": [ + "to_user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "follow_from_user_id_to_user_id": { + "name": "follow_from_user_id_to_user_id", + "columns": [ + "from_user_id", + "to_user_id" + ] + } + } + }, + "identity": { + "name": "identity", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "identity_provider", + "primaryKey": false, + "notNull": true + }, + "external_id": { + "name": "external_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "identity_unq": { + "name": "identity_unq", + "columns": [ + "provider", + "external_id" + ], + "isUnique": true + } + }, + "foreignKeys": { + "identity_user_id_user_id_fk": { + "name": "identity_user_id_user_id_fk", + "tableFrom": "identity", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {} + }, + "tasting": { + "name": "tasting", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "bottle_id": { + "name": "bottle_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "edition_id": { + "name": "edition_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "comments": { + "name": "comments", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tags": { + "name": "tags", + "type": "text[]", + "primaryKey": false, + "notNull": false + }, + "rating": { + "name": "rating", + "type": "double precision", + "primaryKey": false, + "notNull": true + }, + "image_url": { + "name": "image_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "created_by_id": { + "name": "created_by_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "tasting_bottle_id_bottle_id_fk": { + "name": "tasting_bottle_id_bottle_id_fk", + "tableFrom": "tasting", + "tableTo": "bottle", + "columnsFrom": [ + "bottle_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "tasting_edition_id_bottle_id_fk": { + "name": "tasting_edition_id_bottle_id_fk", + "tableFrom": "tasting", + "tableTo": "bottle", + "columnsFrom": [ + "edition_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "tasting_created_by_id_user_id_fk": { + "name": "tasting_created_by_id_user_id_fk", + "tableFrom": "tasting", + "tableTo": "user", + "columnsFrom": [ + "created_by_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {} + }, + "user": { + "name": "user", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "password_hash": { + "name": "password_hash", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "display_name": { + "name": "display_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "picture_url": { + "name": "picture_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "active": { + "name": "active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "admin": { + "name": "admin", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "user_email_unq": { + "name": "user_email_unq", + "columns": [ + "email" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {} + } + }, + "enums": { + "category": { + "name": "category", + "values": { + "blend": "blend", + "bourbon": "bourbon", + "rye": "rye", + "single_grain": "single_grain", + "single_malt": "single_malt", + "spirit": "spirit" + } + }, + "entity_type": { + "name": "entity_type", + "values": { + "brand": "brand", + "distiller": "distiller" + } + }, + "follow_status": { + "name": "follow_status", + "values": { + "none": "none", + "pending": "pending", + "following": "following" + } + }, + "identity_provider": { + "name": "identity_provider", + "values": { + "google": "google" + } + }, + "object_type": { + "name": "object_type", + "values": { + "bottle": "bottle", + "edition": "edition", + "entity": "entity" + } + } + }, + "schemas": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + } +} \ No newline at end of file diff --git a/apps/api/migrations/meta/_journal.json b/apps/api/migrations/meta/_journal.json index 3f4535bc..81df97ad 100644 --- a/apps/api/migrations/meta/_journal.json +++ b/apps/api/migrations/meta/_journal.json @@ -22,6 +22,13 @@ "when": 1683863512362, "tag": "0002_bent_absorbing_man", "breakpoints": false + }, + { + "idx": 3, + "version": "5", + "when": 1683920598362, + "tag": "0003_military_preak", + "breakpoints": false } ] -} +} \ No newline at end of file diff --git a/apps/api/package.json b/apps/api/package.json index 701f12a9..d3dfd87a 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -4,11 +4,11 @@ "scripts": { "build": "tsc", "dev": "nodemon --exec ts-node --require dotenv/config ./src/server.ts", - "dev:load-mocks": "ts-node --require dotenv/config ./src/bin/load-mocks.ts", "db": "ts-node --require dotenv/config ./src/bin/db.ts", "db:deploy": "npm run db:migrate", "db:migrate": "ts-node --require dotenv/config ./src/bin/db.ts migrate", "db:generate": "npx drizzle-kit generate:pg", + "load-mocks": "ts-node --require dotenv/config ./src/bin/load-mocks.ts", "user": "ts-node --require dotenv/config ./src/bin/user.ts", "start": "ts-node --require dotenv/config ./src/server.ts", "typecheck": "tsc --noEmit", diff --git a/apps/api/src/bin/load-mocks.ts b/apps/api/src/bin/load-mocks.ts index b3f74f19..cede6857 100644 --- a/apps/api/src/bin/load-mocks.ts +++ b/apps/api/src/bin/load-mocks.ts @@ -1,11 +1,35 @@ +import { eq, ne } from "drizzle-orm"; +import { db } from "../db"; +import { users } from "../db/schema"; import * as Fixtures from "../lib/test/fixtures"; -const main = async () => { +const main = async (yourUserEmail?: string) => { let bottle; for (let i = 0; i < 100; i++) { bottle = await Fixtures.Bottle(); console.log(`${bottle.name} created.`); } + + if (yourUserEmail) { + const [{ id: toUserId }] = await db + .select() + .from(users) + .where(eq(users.email, yourUserEmail)); + const userList = await db + .select() + .from(users) + .where(ne(users.id, toUserId)) + .limit(5); + + for (const { id: fromUserId } of userList) { + await Fixtures.Follow({ + toUserId, + fromUserId, + status: "pending", + }); + console.log(`Created follow request from ${fromUserId} -> ${toUserId}`); + } + } }; -main(); +main(process.argv[2]); diff --git a/apps/api/src/db/index.ts b/apps/api/src/db/index.ts index a838a1be..b30e8eb4 100644 --- a/apps/api/src/db/index.ts +++ b/apps/api/src/db/index.ts @@ -18,6 +18,11 @@ export const pool = new Pool({ export const db = drizzle(pool, { logger: config.DEBUG }); +export const first = (value: any[]) => { + const [result] = value; + return result; +}; + // export const findFirst = async ( // table: AnyPgTable, // query: { diff --git a/apps/api/src/db/schema.ts b/apps/api/src/db/schema.ts index 525f6f1d..8c0e83e8 100644 --- a/apps/api/src/db/schema.ts +++ b/apps/api/src/db/schema.ts @@ -61,6 +61,34 @@ export const identities = pgTable( }, ); +export const followStatusEnum = pgEnum("follow_status", [ + "none", + "pending", + "following", +]); + +export const follows = pgTable( + "follow", + { + fromUserId: bigint("from_user_id", { mode: "number" }) + .references(() => users.id) + .notNull(), + toUserId: bigint("to_user_id", { mode: "number" }) + .references(() => users.id) + .notNull(), + status: followStatusEnum("status").default("pending").notNull(), + createdAt: timestamp("created_at").defaultNow().notNull(), + }, + (follows) => { + return { + follows: primaryKey(follows.fromUserId, follows.toUserId), + }; + }, +); + +export type Follow = InferModel; +export type NewFollow = InferModel; + export const entityTypeEnum = pgEnum("entity_type", ["brand", "distiller"]); export const entities = pgTable( diff --git a/apps/api/src/lib/db.ts b/apps/api/src/lib/db.ts index f4721f8b..03863b5d 100644 --- a/apps/api/src/lib/db.ts +++ b/apps/api/src/lib/db.ts @@ -1,4 +1,5 @@ import { eq } from "drizzle-orm"; +import { first } from "../db"; import { NewEntity, changes, entities } from "../db/schema"; export type EntityInput = @@ -32,10 +33,9 @@ export const upsertEntity = async ({ if (!data) return undefined; if (typeof data === "number") { - const [result] = await db - .select() - .from(entities) - .where(eq(entities.id, data)); + const result = first( + await db.select().from(entities).where(eq(entities.id, data)), + ); if (result && result.type.indexOf(type) === -1) { await db @@ -46,17 +46,19 @@ export const upsertEntity = async ({ return result ? { id: result.id, result, created: false } : undefined; } - const [result] = await db - .insert(entities) - .values({ - name: data.name, - country: data.country || null, - region: data.region || null, - type: [type], - createdById: userId, - }) - .onConflictDoNothing() - .returning(); + const result = first( + await db + .insert(entities) + .values({ + name: data.name, + country: data.country || null, + region: data.region || null, + type: [type], + createdById: userId, + }) + .onConflictDoNothing() + .returning(), + ); if (result) { await db.insert(changes).values({ @@ -69,10 +71,9 @@ export const upsertEntity = async ({ return { id: result.id, result, created: true }; } - const [resultConflict] = await db - .select() - .from(entities) - .where(eq(entities.name, data.name)); + const resultConflict = first( + await db.select().from(entities).where(eq(entities.name, data.name)), + ); if (resultConflict) return { id: resultConflict.id, result: resultConflict, created: false }; diff --git a/apps/api/src/lib/test/fixtures.ts b/apps/api/src/lib/test/fixtures.ts index 0d245c7c..75ce205b 100644 --- a/apps/api/src/lib/test/fixtures.ts +++ b/apps/api/src/lib/test/fixtures.ts @@ -1,14 +1,17 @@ import { faker } from "@faker-js/faker"; -import { db } from "../../db"; +import { eq } from "drizzle-orm"; +import { db, first } from "../../db"; import { NewBottle, NewEntity, + NewFollow, NewTasting, NewUser, User as UserType, bottles, bottlesToDistillers, entities, + follows, tastings, users, } from "../../db/schema"; @@ -33,19 +36,39 @@ export const User = async ({ ...data }: Partial = {}) => { )[0]; }; -export const Entity = async ({ ...data }: Partial = {}) => { +export const Follow = async ({ ...data }: Partial = {}) => { return ( + await db + .insert(follows) + .values({ + fromUserId: data.fromUserId || (await User()).id, + toUserId: data.toUserId || (await User()).id, + status: "following", + ...data, + }) + .returning() + )[0]; +}; + +export const Entity = async ({ ...data }: Partial = {}) => { + const name = faker.company.name(); + const existing = first( + await db.select().from(entities).where(eq(entities.name, name)), + ); + if (existing) return existing; + + return first( await db .insert(entities) .values({ - name: faker.company.name(), + name, country: faker.address.country(), type: ["brand", "distiller"], ...data, createdById: data.createdById || (await User()).id, }) - .returning() - )[0]; + .returning(), + ); }; export const Bottle = async ({ diff --git a/apps/api/src/lib/transformers/follow.ts b/apps/api/src/lib/transformers/follow.ts new file mode 100644 index 00000000..bec2d469 --- /dev/null +++ b/apps/api/src/lib/transformers/follow.ts @@ -0,0 +1,18 @@ +import { Follow, User } from "../../db/schema"; +import { serializeUser } from "./user"; + +export const serializeFollow = ( + follow: Follow & { + user: User; + followsBack?: Follow | null; + }, + currentUser?: User, +) => { + return { + id: follow.fromUserId, + status: follow.status, + createdAt: follow.createdAt, + user: serializeUser(follow.user, currentUser), + followsBack: follow.followsBack?.status || "none", + }; +}; diff --git a/apps/api/src/lib/transformers/user.ts b/apps/api/src/lib/transformers/user.ts index 60eb3657..7cd2bd00 100644 --- a/apps/api/src/lib/transformers/user.ts +++ b/apps/api/src/lib/transformers/user.ts @@ -8,10 +8,13 @@ export interface SerializedUser { admin?: boolean; email?: string; createdAt?: string; + followStatus?: "none" | "following" | "pending"; } export const serializeUser = ( - user: User, + user: User & { + followStatus?: "none" | "following" | "pending"; + }, currentUser?: User, ): SerializedUser => { const data: SerializedUser = { @@ -20,6 +23,7 @@ export const serializeUser = ( pictureUrl: user.pictureUrl ? `${config.URL_PREFIX}${user.pictureUrl}` : null, + followStatus: user.followStatus, }; if (currentUser && (currentUser.admin || currentUser.id === user.id)) { return { diff --git a/apps/api/src/middleware/auth.ts b/apps/api/src/middleware/auth.ts index 4869d1d0..d7377b55 100644 --- a/apps/api/src/middleware/auth.ts +++ b/apps/api/src/middleware/auth.ts @@ -13,6 +13,8 @@ export const validateRequest: onRequestHookHandler = async (req, res) => { [req.user] = await db.select().from(users).where(eq(users.id, id)); } catch (error) { console.error(error); - return res.status(401).send({ error: "Unauthorized!" }); + return res + .status(401) + .send({ error: "Unauthorized!", name: "invalid_token" }); } }; diff --git a/apps/api/src/routes/entities.test.ts b/apps/api/src/routes/addEntity.test.ts similarity index 53% rename from apps/api/src/routes/entities.test.ts rename to apps/api/src/routes/addEntity.test.ts index face53ff..1835330e 100644 --- a/apps/api/src/routes/entities.test.ts +++ b/apps/api/src/routes/addEntity.test.ts @@ -3,42 +3,14 @@ import { FastifyInstance } from "fastify"; import buildFastify from "../app"; import { db } from "../db"; import { entities } from "../db/schema"; -import * as Fixtures from "../lib/test/fixtures"; let app: FastifyInstance; beforeAll(async () => { app = await buildFastify(); -}); - -afterAll(async () => { - await app.close(); -}); - -test("lists entities", async () => { - await Fixtures.Entity(); - await Fixtures.Entity(); - - const response = await app.inject({ - method: "GET", - url: "/entities", - }); - expect(response).toRespondWith(200); - const { results } = JSON.parse(response.payload); - expect(results.length).toBe(2); -}); - -test("get entity", async () => { - const brand = await Fixtures.Entity(); - - const response = await app.inject({ - method: "GET", - url: `/entities/${brand.id}`, - }); - - expect(response).toRespondWith(200); - const data = JSON.parse(response.payload); - expect(data.id).toBe(brand.id); + return async () => { + await app.close(); + }; }); test("creates a new entity", async () => { diff --git a/apps/api/src/routes/addTasting.test.ts b/apps/api/src/routes/addTasting.test.ts index c965f80b..e4eba92f 100644 --- a/apps/api/src/routes/addTasting.test.ts +++ b/apps/api/src/routes/addTasting.test.ts @@ -8,10 +8,10 @@ import * as Fixtures from "../lib/test/fixtures"; let app: FastifyInstance; beforeAll(async () => { app = await buildFastify(); -}); -afterAll(async () => { - await app.close(); + return async () => { + await app.close(); + }; }); test("creates a new tasting with minimal params", async () => { diff --git a/apps/api/src/routes/getBottle.tsx b/apps/api/src/routes/getBottle.tsx index 0fd1c48a..ea76a667 100644 --- a/apps/api/src/routes/getBottle.tsx +++ b/apps/api/src/routes/getBottle.tsx @@ -2,7 +2,13 @@ import { eq, sql } from "drizzle-orm"; import type { RouteOptions } from "fastify"; import { IncomingMessage, Server, ServerResponse } from "http"; import { db } from "../db"; -import { bottles, bottlesToDistillers, entities, tastings } from "../db/schema"; +import { + bottles, + bottlesToDistillers, + entities, + tastings, + users, +} from "../db/schema"; export default { method: "GET", @@ -17,13 +23,15 @@ export default { }, }, handler: async (req, res) => { - const [{ bottle, brand }] = await db + const [{ bottle, brand, createdBy }] = await db .select({ bottle: bottles, brand: entities, + createdBy: users, }) .from(bottles) .innerJoin(entities, eq(entities.id, bottles.brandId)) + .innerJoin(users, eq(users.id, bottles.createdById)) .where(eq(bottles.id, req.params.bottleId)); if (!bottle) { @@ -57,6 +65,7 @@ export default { res.send({ ...bottle, + createdBy, brand, distillers: distillers.map(({ distiller }) => distiller), stats: { diff --git a/apps/api/src/routes/getEntity.test.ts b/apps/api/src/routes/getEntity.test.ts new file mode 100644 index 00000000..6adc42e6 --- /dev/null +++ b/apps/api/src/routes/getEntity.test.ts @@ -0,0 +1,25 @@ +import { FastifyInstance } from "fastify"; +import buildFastify from "../app"; +import * as Fixtures from "../lib/test/fixtures"; + +let app: FastifyInstance; +beforeAll(async () => { + app = await buildFastify(); + + return async () => { + await app.close(); + }; +}); + +test("get entity", async () => { + const brand = await Fixtures.Entity(); + + const response = await app.inject({ + method: "GET", + url: `/entities/${brand.id}`, + }); + + expect(response).toRespondWith(200); + const data = JSON.parse(response.payload); + expect(data.id).toBe(brand.id); +}); diff --git a/apps/api/src/routes/getUser.test.ts b/apps/api/src/routes/getUser.test.ts index 8ba2f774..6d423511 100644 --- a/apps/api/src/routes/getUser.test.ts +++ b/apps/api/src/routes/getUser.test.ts @@ -23,6 +23,7 @@ test("get user", async () => { expect(response).toRespondWith(200); const data = JSON.parse(response.payload); expect(data.id).toBe(user.id); + expect(data.followStatus).toBe("none"); }); test("get user:me", async () => { @@ -45,3 +46,22 @@ test("get user requires auth", async () => { expect(response).toRespondWith(401); }); + +test("get user w/ followStatus", async () => { + const user = await Fixtures.User(); + await Fixtures.Follow({ + fromUserId: DefaultFixtures.user.id, + toUserId: user.id, + }); + + const response = await app.inject({ + method: "GET", + url: `/users/${user.id}`, + headers: DefaultFixtures.authHeaders, + }); + + expect(response).toRespondWith(200); + const data = JSON.parse(response.payload); + expect(data.id).toBe(user.id); + expect(data.followStatus).toBe("following"); +}); diff --git a/apps/api/src/routes/getUser.ts b/apps/api/src/routes/getUser.ts index 586bb047..f7aa3a0e 100644 --- a/apps/api/src/routes/getUser.ts +++ b/apps/api/src/routes/getUser.ts @@ -1,8 +1,8 @@ -import { eq, sql } from "drizzle-orm"; +import { and, eq, sql } from "drizzle-orm"; import type { RouteOptions } from "fastify"; import { IncomingMessage, Server, ServerResponse } from "http"; import { db } from "../db"; -import { changes, tastings, users } from "../db/schema"; +import { User, changes, follows, tastings, users } from "../db/schema"; import { serializeUser } from "../lib/transformers/user"; import { validateRequest } from "../middleware/auth"; @@ -43,8 +43,28 @@ export default { .from(changes) .where(eq(changes.createdById, user.id)); + const getFollowStatus = async (user: User) => { + const [follow] = await db + .select() + .from(follows) + .where( + and( + eq(follows.fromUserId, req.user.id), + eq(follows.toUserId, user.id), + ), + ); + if (!follow) return "none"; + return follow.status; + }; + res.send({ - ...serializeUser(user, req.user), + ...serializeUser( + { + ...user, + followStatus: await getFollowStatus(user), + }, + req.user, + ), stats: { tastings: totalTastings, bottles: totalBottles, diff --git a/apps/api/src/routes/index.ts b/apps/api/src/routes/index.ts index 3e628d9d..eb6a2c95 100644 --- a/apps/api/src/routes/index.ts +++ b/apps/api/src/routes/index.ts @@ -12,13 +12,17 @@ import getTasting from "./getTasting"; import getUser from "./getUser"; import listBottles from "./listBottles"; import listEntities from "./listEntities"; +import listFollowers from "./listFollowers"; import listTastings from "./listTastings"; import listUsers from "./listUsers"; import updateBottle from "./updateBottle"; +import updateFollower from "./updateFollower"; import updateTastingImage from "./updateTastingImage"; import updateUser from "./updateUser"; import updateUserAvatar from "./updateUserAvatar"; import getUpload from "./uploads"; +import userFollow from "./userFollow"; +import userUnfollow from "./userUnfollow"; export const router: FastifyPluginCallback = ( fastify: FastifyInstance, @@ -62,6 +66,10 @@ export const router: FastifyPluginCallback = ( fastify.route(getUser); fastify.route(updateUser); fastify.route(updateUserAvatar); + fastify.route(userFollow); + fastify.route(userUnfollow); + fastify.route(listFollowers); + fastify.route(updateFollower); fastify.route(getUpload); diff --git a/apps/api/src/routes/listEntities.test.ts b/apps/api/src/routes/listEntities.test.ts new file mode 100644 index 00000000..6ad1e49f --- /dev/null +++ b/apps/api/src/routes/listEntities.test.ts @@ -0,0 +1,26 @@ +import { FastifyInstance } from "fastify"; +import buildFastify from "../app"; +import * as Fixtures from "../lib/test/fixtures"; + +let app: FastifyInstance; +beforeAll(async () => { + app = await buildFastify(); + + return async () => { + await app.close(); + }; +}); + +test("lists entities", async () => { + await Fixtures.Entity(); + await Fixtures.Entity(); + + const response = await app.inject({ + method: "GET", + url: "/entities", + }); + + expect(response).toRespondWith(200); + const { results } = JSON.parse(response.payload); + expect(results.length).toBe(2); +}); diff --git a/apps/api/src/routes/listFollowers.test.ts b/apps/api/src/routes/listFollowers.test.ts new file mode 100644 index 00000000..d693778c --- /dev/null +++ b/apps/api/src/routes/listFollowers.test.ts @@ -0,0 +1,53 @@ +import { FastifyInstance } from "fastify"; +import buildFastify from "../app"; +import * as Fixtures from "../lib/test/fixtures"; + +let app: FastifyInstance; +beforeAll(async () => { + app = await buildFastify(); + + return async () => { + app.close(); + }; +}); + +test("lists followers", async () => { + const follow1 = await Fixtures.Follow({ + toUserId: DefaultFixtures.user.id, + }); + const follow2 = await Fixtures.Follow({ + toUserId: DefaultFixtures.user.id, + }); + + const response = await app.inject({ + method: "GET", + url: "/users/me/followers", + headers: DefaultFixtures.authHeaders, + }); + + expect(response).toRespondWith(200); + const { results } = JSON.parse(response.payload); + expect(results.length).toBe(2); +}); + +test("lists follow requests requires auth", async () => { + const response = await app.inject({ + method: "GET", + url: "/users/me/followers", + }); + + expect(response).toRespondWith(401); +}); + +test("lists follow requests cannot query others", async () => { + const user = await Fixtures.User(); + const otherUser = await Fixtures.User(); + + const response = await app.inject({ + method: "GET", + url: `/users/${otherUser.id}/followers`, + headers: await Fixtures.AuthenticatedHeaders({ user }), + }); + + expect(response).toRespondWith(403); +}); diff --git a/apps/api/src/routes/listFollowers.ts b/apps/api/src/routes/listFollowers.ts new file mode 100644 index 00000000..56eb38c8 --- /dev/null +++ b/apps/api/src/routes/listFollowers.ts @@ -0,0 +1,102 @@ +import { and, asc, eq } from "drizzle-orm"; +import { alias } from "drizzle-orm/pg-core"; +import type { RouteOptions } from "fastify"; +import { IncomingMessage, Server, ServerResponse } from "http"; +import { db } from "../db"; +import { follows, users } from "../db/schema"; +import { buildPageLink } from "../lib/paging"; +import { serializeFollow } from "../lib/transformers/follow"; +import { validateRequest } from "../middleware/auth"; + +export default { + method: "GET", + url: "/users/:userId/followers", + schema: { + params: { + type: "object", + required: ["userId"], + properties: { + userId: { oneOf: [{ type: "number" }, { const: "me" }] }, + }, + }, + querystring: { + type: "object", + properties: { + query: { type: "string" }, + page: { type: "number" }, + status: { type: "string", enum: ["pending", "following"] }, + }, + }, + }, + preHandler: [validateRequest], + handler: async (req, res) => { + const userId = req.params.userId === "me" ? req.user.id : req.params.userId; + + const [user] = await db.select().from(users).where(eq(users.id, userId)); + + if (!user) { + return res.status(404).send({ error: "Not found" }); + } + + if (user.id !== req.user.id && !user.admin) { + return res.status(403).send({ error: "Forbidden" }); + } + + const page = req.query.page || 1; + const limit = 100; + const offset = (page - 1) * limit; + + const where = [eq(follows.toUserId, user.id)]; + if (req.query.status) { + where.push(eq(follows.status, req.query.status)); + } + + const followsBack = alias(follows, "follows_back"); + const results = await db + .select({ + user: users, + follow: follows, + followsBack: followsBack, + }) + .from(follows) + .where(and(...where)) + .innerJoin(users, eq(users.id, follows.fromUserId)) + .leftJoin(followsBack, eq(users.id, followsBack.toUserId)) + .limit(limit + 1) + .offset(offset) + .orderBy(asc(follows.status), asc(follows.createdAt)); + + res.send({ + results: results.slice(0, limit).map(({ user, follow, followsBack }) => + serializeFollow({ + ...follow, + followsBack, + user, + }), + ), + rel: { + next: + results.length > limit + ? buildPageLink(req.routeOptions.url, req.query, page + 1) + : null, + prev: + page > 1 + ? buildPageLink(req.routeOptions.url, req.query, page - 1) + : null, + }, + }); + }, +} as RouteOptions< + Server, + IncomingMessage, + ServerResponse, + { + Params: { + userId: number | "me"; + }; + Querystring: { + page?: number; + status?: "pending" | "following"; + }; + } +>; diff --git a/apps/api/src/routes/listTastings.test.ts b/apps/api/src/routes/listTastings.test.ts index b66ea284..fca01577 100644 --- a/apps/api/src/routes/listTastings.test.ts +++ b/apps/api/src/routes/listTastings.test.ts @@ -5,10 +5,10 @@ import * as Fixtures from "../lib/test/fixtures"; let app: FastifyInstance; beforeAll(async () => { app = await buildFastify(); -}); -afterAll(async () => { - await app.close(); + return async () => { + app.close(); + }; }); test("lists tastings", async () => { @@ -21,8 +21,8 @@ test("lists tastings", async () => { }); expect(response).toRespondWith(200); - const data = JSON.parse(response.payload); - expect(data.length).toBe(2); + const { results } = JSON.parse(response.payload); + expect(results.length).toBe(2); }); test("lists tastings with bottle", async () => { @@ -39,9 +39,9 @@ test("lists tastings with bottle", async () => { }); expect(response).toRespondWith(200); - const data = JSON.parse(response.payload); - expect(data.length).toBe(1); - expect(data[0].id).toBe(tasting.id); + const { results } = JSON.parse(response.payload); + expect(results.length).toBe(1); + expect(results[0].id).toBe(tasting.id); }); test("lists tastings with user", async () => { @@ -59,7 +59,48 @@ test("lists tastings with user", async () => { }); expect(response).toRespondWith(200); - const data = JSON.parse(response.payload); - expect(data.length).toBe(1); - expect(data[0].id).toBe(tasting.id); + const { results } = JSON.parse(response.payload); + expect(results.length).toBe(1); + expect(results[0].id).toBe(tasting.id); +}); + +test("lists tastings filter friends unauthenticated", async () => { + await Fixtures.Tasting(); + await Fixtures.Tasting(); + + const response = await app.inject({ + method: "GET", + url: "/tastings", + query: { + filter: "friends", + }, + }); + + expect(response).toRespondWith(401); +}); + +test("lists tastings filter friends", async () => { + await Fixtures.Tasting(); + await Fixtures.Tasting(); + + const otherUser = await Fixtures.User(); + await Fixtures.Follow({ + fromUserId: DefaultFixtures.user.id, + toUserId: otherUser.id, + status: "following", + }); + const lastTasting = await Fixtures.Tasting({ createdById: otherUser.id }); + + const response = await app.inject({ + method: "GET", + url: "/tastings", + query: { + filter: "friends", + }, + }); + + expect(response).toRespondWith(200); + const { results } = JSON.parse(response.payload); + expect(results.length).toBe(1); + expect(results[0].id).toBe(lastTasting.id); }); diff --git a/apps/api/src/routes/listTastings.ts b/apps/api/src/routes/listTastings.ts index 16447795..d1540731 100644 --- a/apps/api/src/routes/listTastings.ts +++ b/apps/api/src/routes/listTastings.ts @@ -1,4 +1,4 @@ -import { SQL, and, desc, eq, inArray } from "drizzle-orm"; +import { SQL, and, desc, eq, inArray, sql } from "drizzle-orm"; import type { RouteOptions } from "fastify"; import { IncomingMessage, Server, ServerResponse } from "http"; import { db } from "../db"; @@ -8,9 +8,11 @@ import { bottlesToDistillers, editions, entities, + follows, tastings, users, } from "../db/schema"; +import { buildPageLink } from "../lib/paging"; import { serializeTasting } from "../lib/transformers/tasting"; export default { @@ -40,6 +42,16 @@ export default { if (req.query.user) { where.push(eq(tastings.createdById, req.query.user)); } + if (req.query.filter) { + if (req.query.filter === "friends") { + if (!req.user) { + return res.status(401).send({ error: "Not authenticated" }); + } + where.push( + sql`${tastings.createdById} IN (SELECT ${follows.toUserId} FROM ${follows} WHERE ${follows.fromUserId} = ${req.user.id} AND ${follows.status} == 'following')`, + ); + } + } const results = await db .select({ @@ -87,23 +99,35 @@ export default { else distillersByBottleId[d.bottleId].push(d.distiller); }); - res.send( - results.map(({ tasting, bottle, brand, createdBy, edition }) => - serializeTasting( - { - ...tasting, - createdBy, - edition, - bottle: { - ...bottle, - brand, - distillers: distillersByBottleId[bottle.id], + res.send({ + results: results + .slice(0, limit) + .map(({ tasting, bottle, brand, createdBy, edition }) => + serializeTasting( + { + ...tasting, + createdBy, + edition, + bottle: { + ...bottle, + brand, + distillers: distillersByBottleId[bottle.id], + }, }, - }, - req.user, + req.user, + ), ), - ), - ); + rel: { + next: + results.length > limit + ? buildPageLink(req.routeOptions.url, req.query, page + 1) + : null, + prev: + page > 1 + ? buildPageLink(req.routeOptions.url, req.query, page - 1) + : null, + }, + }); }, } as RouteOptions< Server, @@ -114,6 +138,7 @@ export default { page?: number; bottle?: number; user?: number; + filter?: "global" | "friends" | "local"; }; } >; diff --git a/apps/api/src/routes/listUsers.test.ts b/apps/api/src/routes/listUsers.test.ts index c9c7d29b..48c3b808 100644 --- a/apps/api/src/routes/listUsers.test.ts +++ b/apps/api/src/routes/listUsers.test.ts @@ -21,8 +21,8 @@ test("lists users", async () => { }); expect(response).toRespondWith(200); - const data = JSON.parse(response.payload); - expect(data.length).toBe(2); + const { results } = JSON.parse(response.payload); + expect(results.length).toBe(2); }); test("lists users requires auth", async () => { diff --git a/apps/api/src/routes/listUsers.ts b/apps/api/src/routes/listUsers.ts index ab5403b4..46b94290 100644 --- a/apps/api/src/routes/listUsers.ts +++ b/apps/api/src/routes/listUsers.ts @@ -3,6 +3,7 @@ import type { RouteOptions } from "fastify"; import { IncomingMessage, Server, ServerResponse } from "http"; import { db } from "../db"; import { users } from "../db/schema"; +import { buildPageLink } from "../lib/paging"; import { serializeUser } from "../lib/transformers/user"; import { validateRequest } from "../middleware/auth"; @@ -41,7 +42,19 @@ export default { .offset(offset) .orderBy(asc(users.displayName)); - res.send(results.map((u) => serializeUser(u, req.user))); + res.send({ + results: results.map((u) => serializeUser(u, req.user)), + rel: { + next: + results.length > limit + ? buildPageLink(req.routeOptions.url, req.query, page + 1) + : null, + prev: + page > 1 + ? buildPageLink(req.routeOptions.url, req.query, page - 1) + : null, + }, + }); }, } as RouteOptions< Server, diff --git a/apps/api/src/routes/updateFollower.test.ts b/apps/api/src/routes/updateFollower.test.ts new file mode 100644 index 00000000..88797e88 --- /dev/null +++ b/apps/api/src/routes/updateFollower.test.ts @@ -0,0 +1,68 @@ +import { and, eq } from "drizzle-orm"; +import { FastifyInstance } from "fastify"; +import buildFastify from "../app"; +import { db } from "../db"; +import { follows } from "../db/schema"; +import * as Fixtures from "../lib/test/fixtures"; + +let app: FastifyInstance; +beforeAll(async () => { + app = await buildFastify(); + + return async () => { + await app.close(); + }; +}); + +test("cannot act others requests", async () => { + const user = await Fixtures.User(); + const otherUser = await Fixtures.User(); + + const follow = await Fixtures.Follow({ + fromUserId: otherUser.id, + toUserId: user.id, + }); + + const response = await app.inject({ + method: "PUT", + url: `/users/${otherUser.id}/followers/${user.id}`, + payload: { + action: "accept", + }, + headers: await Fixtures.AuthenticatedHeaders({ user }), + }); + + expect(response).toRespondWith(403); +}); + +test("can accept request", async () => { + const user = await Fixtures.User(); + const otherUser = await Fixtures.User(); + + const follow = await Fixtures.Follow({ + fromUserId: otherUser.id, + toUserId: user.id, + }); + + const response = await app.inject({ + method: "PUT", + url: `/users/${user.id}/followers/${otherUser.id}`, + payload: { + action: "accept", + }, + headers: await Fixtures.AuthenticatedHeaders({ user }), + }); + + expect(response).toRespondWith(200); + const data = JSON.parse(response.payload); + expect(data.status).toBe("following"); + expect(data.followsBack).toBe("none"); + + const [newFollow] = await db + .select() + .from(follows) + .where( + and(eq(follows.toUserId, user.id), eq(follows.fromUserId, otherUser.id)), + ); + expect(newFollow.status).toBe("following"); +}); diff --git a/apps/api/src/routes/updateFollower.ts b/apps/api/src/routes/updateFollower.ts new file mode 100644 index 00000000..c58e379c --- /dev/null +++ b/apps/api/src/routes/updateFollower.ts @@ -0,0 +1,105 @@ +import { and, eq } from "drizzle-orm"; +import { alias } from "drizzle-orm/pg-core"; +import type { RouteOptions } from "fastify"; +import { IncomingMessage, Server, ServerResponse } from "http"; +import { db, first } from "../db"; +import { follows, users } from "../db/schema"; +import { serializeFollow } from "../lib/transformers/follow"; +import { validateRequest } from "../middleware/auth"; + +export default { + method: "PUT", + url: "/users/:userId/followers/:fromUserId", + schema: { + params: { + type: "object", + required: ["userId", "fromUserId"], + properties: { + userId: { oneOf: [{ type: "number" }, { const: "me" }] }, + fromUserId: { type: "number" }, + }, + }, + body: { + type: "object", + required: ["action"], + properties: { + action: { type: "string", enum: ["accept"] }, + }, + }, + }, + preHandler: [validateRequest], + handler: async (req, res) => { + const userId = req.params.userId === "me" ? req.user.id : req.params.userId; + + const [user] = await db.select().from(users).where(eq(users.id, userId)); + + if (!user) { + return res.status(404).send({ error: "Not found" }); + } + + if (user.id !== req.user.id && !user.admin) { + return res.status(403).send({ error: "Forbidden" }); + } + + const followsBackTable = alias(follows, "follows_back"); + const result = first( + await db + .select({ + followUser: users, + follow: follows, + followsBack: followsBackTable, + }) + .from(follows) + .innerJoin(users, eq(users.id, follows.fromUserId)) + .leftJoin(followsBackTable, eq(users.id, followsBackTable.toUserId)) + .where( + and( + eq(follows.fromUserId, req.params.fromUserId), + eq(follows.toUserId, user.id), + ), + ), + ); + + if (!result) { + return res.status(404).send({ error: "Not found" }); + } + const { follow, followUser, followsBack } = result; + + const [newFollow] = await db + .update(follows) + .set({ + status: req.body.action === "accept" ? "following" : follow.status, + }) + .where( + and( + eq(follows.fromUserId, req.params.fromUserId), + eq(follows.toUserId, user.id), + ), + ) + .returning(); + + res.send( + serializeFollow( + { + ...newFollow, + user: followUser, + followsBack: followsBack?.status || "none", + }, + req.user, + ), + ); + }, +} as RouteOptions< + Server, + IncomingMessage, + ServerResponse, + { + Params: { + userId: number | "me"; + fromUserId: number; + }; + Body: { + action: "accept"; + }; + } +>; diff --git a/apps/api/src/routes/updateUser.test.ts b/apps/api/src/routes/updateUser.test.ts new file mode 100644 index 00000000..e4c80935 --- /dev/null +++ b/apps/api/src/routes/updateUser.test.ts @@ -0,0 +1,52 @@ +import { eq } from "drizzle-orm"; +import { FastifyInstance } from "fastify"; +import buildFastify from "../app"; +import { db } from "../db"; +import { users } from "../db/schema"; +import * as Fixtures from "../lib/test/fixtures"; + +let app: FastifyInstance; +beforeAll(async () => { + app = await buildFastify(); + + return async () => { + await app.close(); + }; +}); + +test("cannot update another user", async () => { + const user = await Fixtures.User(); + const otherUser = await Fixtures.User(); + + const response = await app.inject({ + method: "PUT", + url: `/users/${otherUser.id}`, + payload: { + displayName: "Joe", + }, + headers: await Fixtures.AuthenticatedHeaders({ user }), + }); + + expect(response).toRespondWith(403); +}); + +test("can change displayName", async () => { + const response = await app.inject({ + method: "PUT", + url: `/users/${DefaultFixtures.user.id}`, + payload: { + displayName: "Joe", + }, + headers: DefaultFixtures.authHeaders, + }); + + expect(response).toRespondWith(200); + const data = JSON.parse(response.payload); + expect(data.id).toBeDefined(); + + const [user] = await db + .select() + .from(users) + .where(eq(users.id, DefaultFixtures.user.id)); + expect(user.displayName).toEqual("Joe"); +}); diff --git a/apps/api/src/routes/userFollow.test.ts b/apps/api/src/routes/userFollow.test.ts new file mode 100644 index 00000000..9767deba --- /dev/null +++ b/apps/api/src/routes/userFollow.test.ts @@ -0,0 +1,83 @@ +import { and, eq } from "drizzle-orm"; +import { FastifyInstance } from "fastify"; +import buildFastify from "../app"; +import { db } from "../db"; +import { follows } from "../db/schema"; +import * as Fixtures from "../lib/test/fixtures"; + +let app: FastifyInstance; +beforeAll(async () => { + app = await buildFastify(); + + return async () => { + await app.close(); + }; +}); + +test("cannot follow self", async () => { + const response = await app.inject({ + method: "POST", + url: `/users/${DefaultFixtures.user.id}/follow`, + headers: DefaultFixtures.authHeaders, + }); + + expect(response).toRespondWith(400); +}); + +test("can follow new link", async () => { + const otherUser = await Fixtures.User(); + + const response = await app.inject({ + method: "POST", + url: `/users/${otherUser.id}/follow`, + headers: DefaultFixtures.authHeaders, + }); + + expect(response).toRespondWith(200); + const data = JSON.parse(response.payload); + expect(data.status).toBe("pending"); + + const [follow] = await db + .select() + .from(follows) + .where( + and( + eq(follows.fromUserId, DefaultFixtures.user.id), + eq(follows.toUserId, otherUser.id), + ), + ); + expect(follow).toBeDefined(); + expect(follow.status).toBe("pending"); +}); + +test("can follow existing link", async () => { + const otherUser = await Fixtures.User(); + + const follow = await Fixtures.Follow({ + fromUserId: DefaultFixtures.user.id, + toUserId: otherUser.id, + status: "following", + }); + + const response = await app.inject({ + method: "POST", + url: `/users/${otherUser.id}/follow`, + headers: DefaultFixtures.authHeaders, + }); + + expect(response).toRespondWith(200); + const data = JSON.parse(response.payload); + expect(data.status).toBe("following"); + + const [newFollow] = await db + .select() + .from(follows) + .where( + and( + eq(follows.fromUserId, DefaultFixtures.user.id), + eq(follows.toUserId, otherUser.id), + ), + ); + expect(newFollow).toBeDefined(); + expect(newFollow.status).toBe(follow.status); +}); diff --git a/apps/api/src/routes/userFollow.ts b/apps/api/src/routes/userFollow.ts new file mode 100644 index 00000000..f1f91764 --- /dev/null +++ b/apps/api/src/routes/userFollow.ts @@ -0,0 +1,86 @@ +import { and, eq } from "drizzle-orm"; +import type { RouteOptions } from "fastify"; +import { IncomingMessage, Server, ServerResponse } from "http"; +import { db, first } from "../db"; +import { follows, users } from "../db/schema"; +import { validateRequest } from "../middleware/auth"; + +export default { + method: "POST", + url: "/users/:userId/follow", + schema: { + params: { + type: "object", + required: ["userId"], + properties: { + userId: { type: "number" }, + }, + }, + }, + preHandler: [validateRequest], + handler: async (req, res) => { + if (req.user.id === req.params.userId) { + return res.status(400).send({ error: "Cannot follow yourself" }); + } + + const [user] = await db + .select() + .from(users) + .where(eq(users.id, req.params.userId)); + + if (!user) { + return res.status(404).send({ error: "Not found" }); + } + + const follow = + first( + await db + .insert(follows) + .values({ + fromUserId: req.user.id, + toUserId: user.id, + }) + .onConflictDoNothing() + .returning(), + ) || + first( + await db + .update(follows) + .set({ + status: "pending", + }) + .where( + and( + eq(follows.status, "none"), + eq(follows.fromUserId, req.user.id), + eq(follows.toUserId, user.id), + ), + ) + .returning(), + ) || + first( + await db + .select() + .from(follows) + .where( + and( + eq(follows.fromUserId, req.user.id), + eq(follows.toUserId, user.id), + ), + ), + ); + + res.status(200).send({ + status: follow.status, + }); + }, +} as RouteOptions< + Server, + IncomingMessage, + ServerResponse, + { + Params: { + userId: number; + }; + } +>; diff --git a/apps/api/src/routes/userUnfollow.test.ts b/apps/api/src/routes/userUnfollow.test.ts new file mode 100644 index 00000000..5e8308e8 --- /dev/null +++ b/apps/api/src/routes/userUnfollow.test.ts @@ -0,0 +1,81 @@ +import { and, eq } from "drizzle-orm"; +import { FastifyInstance } from "fastify"; +import buildFastify from "../app"; +import { db } from "../db"; +import { follows } from "../db/schema"; +import * as Fixtures from "../lib/test/fixtures"; + +let app: FastifyInstance; +beforeAll(async () => { + app = await buildFastify(); + + return async () => { + await app.close(); + }; +}); + +test("cannot unfollow self", async () => { + const response = await app.inject({ + method: "POST", + url: `/users/${DefaultFixtures.user.id}/unfollow`, + headers: DefaultFixtures.authHeaders, + }); + + expect(response).toRespondWith(400); +}); + +test("can unfollow new link", async () => { + const otherUser = await Fixtures.User(); + + const response = await app.inject({ + method: "POST", + url: `/users/${otherUser.id}/unfollow`, + headers: DefaultFixtures.authHeaders, + }); + + expect(response).toRespondWith(200); + const data = JSON.parse(response.payload); + expect(data.status).toBe("none"); + + const [follow] = await db + .select() + .from(follows) + .where( + and( + eq(follows.fromUserId, DefaultFixtures.user.id), + eq(follows.toUserId, otherUser.id), + ), + ); + expect(follow).toBeUndefined(); +}); + +test("can unfollow existing link", async () => { + const otherUser = await Fixtures.User(); + + await Fixtures.Follow({ + fromUserId: DefaultFixtures.user.id, + toUserId: otherUser.id, + }); + + const response = await app.inject({ + method: "POST", + url: `/users/${otherUser.id}/unfollow`, + headers: DefaultFixtures.authHeaders, + }); + + expect(response).toRespondWith(200); + const data = JSON.parse(response.payload); + expect(data.status).toBe("none"); + + const [follow] = await db + .select() + .from(follows) + .where( + and( + eq(follows.fromUserId, DefaultFixtures.user.id), + eq(follows.toUserId, otherUser.id), + ), + ); + expect(follow).toBeDefined(); + expect(follow.status).toBe("none"); +}); diff --git a/apps/api/src/routes/userUnfollow.ts b/apps/api/src/routes/userUnfollow.ts new file mode 100644 index 00000000..d45a69a2 --- /dev/null +++ b/apps/api/src/routes/userUnfollow.ts @@ -0,0 +1,57 @@ +import { and, eq } from "drizzle-orm"; +import type { RouteOptions } from "fastify"; +import { IncomingMessage, Server, ServerResponse } from "http"; +import { db } from "../db"; +import { follows, users } from "../db/schema"; +import { validateRequest } from "../middleware/auth"; + +export default { + method: "POST", + url: "/users/:userId/unfollow", + schema: { + params: { + type: "object", + required: ["userId"], + properties: { + userId: { type: "number" }, + }, + }, + }, + preHandler: [validateRequest], + handler: async (req, res) => { + if (req.user.id === req.params.userId) { + return res.status(400).send({ error: "Cannot unfollow yourself" }); + } + + const [user] = await db + .select() + .from(users) + .where(eq(users.id, req.params.userId)); + + if (!user) { + return res.status(404).send({ error: "Not found" }); + } + + await db + .update(follows) + .set({ + status: "none", + }) + .where( + and(eq(follows.fromUserId, req.user.id), eq(follows.toUserId, user.id)), + ); + + res.status(200).send({ + status: "none", + }); + }, +} as RouteOptions< + Server, + IncomingMessage, + ServerResponse, + { + Params: { + userId: number; + }; + } +>; diff --git a/apps/web/package.json b/apps/web/package.json index 678be4a8..fc7a6167 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -24,6 +24,7 @@ "@vitejs/plugin-react": "^4.0.0", "autoprefixer": "^10.4.14", "date-fns": "^2.30.0", + "dayjs": "^1.11.7", "framer-motion": "^10.12.8", "postcss": "^8.4.23", "react": "^18.2.0", diff --git a/apps/web/src/components/appHeader.tsx b/apps/web/src/components/appHeader.tsx index 3e65930c..f471dfd7 100644 --- a/apps/web/src/components/appHeader.tsx +++ b/apps/web/src/components/appHeader.tsx @@ -1,10 +1,11 @@ import { Menu, Transition } from "@headlessui/react"; -import { Fragment, useState } from "react"; +import { Fragment, useEffect, useState } from "react"; import { Link, useNavigate } from "react-router-dom"; import { ReactComponent as PeatedGlyph } from "../assets/glyph.svg"; import { ReactComponent as PeatedLogo } from "../assets/logo.svg"; import useAuth from "../hooks/useAuth"; +import api from "../lib/api"; import UserAvatar from "./userAvatar"; const HeaderLogo = () => { @@ -30,6 +31,19 @@ export default function AppHeader() { const [query, setQuery] = useState(""); + const [followRequestCount, setFollowRequestCount] = useState(0); + + useEffect(() => { + (async () => { + const { results } = await api.get("/users/me/followers", { + query: { + status: "pending", + }, + }); + setFollowRequestCount(results.length); + })(); + }); + return ( <> @@ -52,11 +66,16 @@ export default function AppHeader() {
- + Open user menu + {followRequestCount > 0 && ( +
+ {followRequestCount.toLocaleString()} +
+ )}
+ + + Friends + {followRequestCount > 0 && ( +
+ {followRequestCount} +
+ )} + +
{ - return ( - - ); -}; - export default ({ tasting, noBottle, @@ -49,7 +34,10 @@ export default ({ > {tasting.createdBy.displayName} - +
diff --git a/apps/web/src/components/timeSince.tsx b/apps/web/src/components/timeSince.tsx new file mode 100644 index 00000000..9138c9a2 --- /dev/null +++ b/apps/web/src/components/timeSince.tsx @@ -0,0 +1,15 @@ +import dayjs from "dayjs"; +import DayJsRelativeTime from "dayjs/plugin/relativeTime"; + +dayjs.extend(DayJsRelativeTime); + +export default ({ + date, + ...props +}: { date: string } & React.ComponentProps<"time">) => { + return ( + + ); +}; diff --git a/apps/web/src/error-page.tsx b/apps/web/src/error-page.tsx index 29b4b95f..f1c9286b 100644 --- a/apps/web/src/error-page.tsx +++ b/apps/web/src/error-page.tsx @@ -1,14 +1,25 @@ import { Link, isRouteErrorResponse, useRouteError } from "react-router-dom"; + import Layout from "./components/layout"; import config from "./config"; +import useAuth from "./hooks/useAuth"; import { useOnlineStatus } from "./hooks/useOnlineStatus"; -import { ApiUnavailable } from "./lib/api"; +import { ApiUnauthorized, ApiUnavailable } from "./lib/api"; export default function ErrorPage() { const error: any = useRouteError(); const isOnline = useOnlineStatus(); + const { logout } = useAuth(); + + if (error instanceof ApiUnauthorized && error.data.name === "invalid_token") { + // need middleware! + logout(); + location.href = "/login"; + return null; + } + let title = "Error"; let subtitle = "Sorry, an unexpected error has occurred."; if (error instanceof ApiUnavailable) { @@ -16,6 +27,10 @@ export default function ErrorPage() { subtitle = isOnline ? "It looks like Peated's API is unreachable right now. Please try again shortly." : "It looks like your network is offline."; + } else if (error instanceof ApiUnauthorized) { + title = "Identify Yourself"; + subtitle = + "To get to where you're going we need you to tell us who you are. We don't just let anyone in here."; } else if (isRouteErrorResponse(error)) { if (error.status === 404) { title = "Not Found"; diff --git a/apps/web/src/lib/api.tsx b/apps/web/src/lib/api.tsx index 0ede8273..885685ab 100644 --- a/apps/web/src/lib/api.tsx +++ b/apps/web/src/lib/api.tsx @@ -27,6 +27,8 @@ export class ApiError extends Error { export class ApiUnavailable extends Error {} +export class ApiUnauthorized extends ApiError {} + const withoutUndefined = (obj: object) => { return Object.fromEntries( Object.entries(obj).filter(([, v]) => v !== undefined), @@ -89,6 +91,9 @@ class ApiClient { throw new ApiUnavailable("Unable to reach API service."); } if (!resp?.ok) { + if (resp.status === 401) { + throw new ApiUnauthorized("Unauthorized", resp, await resp.json()); + } throw new ApiError("Request failed", resp, await resp.json()); } return await resp.json(); diff --git a/apps/web/src/routes.tsx b/apps/web/src/routes.tsx index 65e19577..b2e491fa 100644 --- a/apps/web/src/routes.tsx +++ b/apps/web/src/routes.tsx @@ -19,6 +19,7 @@ import DistillerList, { loader as distillerListLoader, } from "./routes/distillers"; import EditBottle, { loader as editBottleLoader } from "./routes/editBottle"; +import Followers, { loader as followersLoader } from "./routes/followers"; import Login from "./routes/login"; import Root from "./routes/root"; import Search from "./routes/search"; @@ -78,6 +79,11 @@ export default function createRoutes() { element: , loader: distillerDetailsLoader, }, + { + path: "followers", + element: , + loader: followersLoader, + }, { path: "search", element: , diff --git a/apps/web/src/routes/activity.tsx b/apps/web/src/routes/activity.tsx index 91e9e808..450209f8 100644 --- a/apps/web/src/routes/activity.tsx +++ b/apps/web/src/routes/activity.tsx @@ -13,7 +13,7 @@ type LoaderData = { }; export const loader: LoaderFunction = async (): Promise => { - const tastingList = await api.get("/tastings"); + const { results: tastingList } = await api.get("/tastings"); return { tastingList }; }; diff --git a/apps/web/src/routes/bottleDetails.tsx b/apps/web/src/routes/bottleDetails.tsx index a3340e01..abd6f69d 100644 --- a/apps/web/src/routes/bottleDetails.tsx +++ b/apps/web/src/routes/bottleDetails.tsx @@ -5,6 +5,7 @@ import BottleName from "../components/bottleName"; import Button from "../components/button"; import Layout from "../components/layout"; import TastingListItem from "../components/tastingListItem"; +import TimeSince from "../components/timeSince"; import api from "../lib/api"; import { formatCategoryName } from "../lib/strings"; import type { Bottle, Tasting } from "../types"; @@ -67,16 +68,14 @@ export default function BottleDetails() { const { distillers } = bottle; return ( -
+

-

+

Produced by{" "} - - {bottle.brand.name} - + {bottle.brand.name} {distillers.length > 0 && (distillers.length > 0 || bottle.brand.name !== distillers[0].name) && ( @@ -118,7 +117,7 @@ export default function BottleDetails() {

{stats.map((stat) => (
-

{stat.name}

+

{stat.name}

{stat.value}

@@ -135,6 +134,15 @@ export default function BottleDetails() { ) : ( )} + {bottle.createdBy && ( +

+ This bottle was first added by{" "} + + {bottle.createdBy.displayName} + {" "} + +

+ )} ); } diff --git a/apps/web/src/routes/brandDetails.tsx b/apps/web/src/routes/brandDetails.tsx index d585563b..2e5c49ab 100644 --- a/apps/web/src/routes/brandDetails.tsx +++ b/apps/web/src/routes/brandDetails.tsx @@ -38,7 +38,7 @@ export default function BrandDetails() {

{brand.name}

-

+

Located in {brand.country} {brand.region && · {brand.region}}

diff --git a/apps/web/src/routes/editBottle.tsx b/apps/web/src/routes/editBottle.tsx index 74df142f..614d135f 100644 --- a/apps/web/src/routes/editBottle.tsx +++ b/apps/web/src/routes/editBottle.tsx @@ -79,7 +79,6 @@ export default function EditBottle() { e.preventDefault(); (async () => { try { - console.log(formData); await api.put(`/bottles/${bottle.id}`, { data: { ...formData, diff --git a/apps/web/src/routes/followers.tsx b/apps/web/src/routes/followers.tsx new file mode 100644 index 00000000..b7bcf15d --- /dev/null +++ b/apps/web/src/routes/followers.tsx @@ -0,0 +1,114 @@ +import type { LoaderFunction } from "react-router-dom"; +import { useLoaderData } from "react-router-dom"; + +import { useState } from "react"; +import { Link } from "react-router-dom"; +import Button from "../components/button"; +import Layout from "../components/layout"; +import ListItem from "../components/listItem"; +import TimeSince from "../components/timeSince"; +import UserAvatar from "../components/userAvatar"; +import api from "../lib/api"; +import type { FollowRequest, FollowStatus } from "../types"; + +type LoaderData = { + requestList: FollowRequest[]; +}; + +// TODO: when this executes the apiClient has not configured +// its token yet as react-dom (thus context) seemingly has +// not rendered.. so this errors out +export const loader: LoaderFunction = async (): Promise => { + const { results: requestList } = await api.get(`/users/me/followers`); + + return { requestList }; +}; + +export default function Followers() { + const { requestList } = useLoaderData() as LoaderData; + + const [theirFollowStatus, setTheirFollowStatus] = useState< + Record + >(Object.fromEntries(requestList.map((r) => [r.id, r.status]))); + + const [myFollowStatus, setMyFollowStatus] = useState< + Record + >(Object.fromEntries(requestList.map((r) => [r.user.id, r.followsBack]))); + + const acceptRequest = async (id: string) => { + const data = await api.put(`/users/me/followers/${id}`, { + data: { action: "accept" }, + }); + setTheirFollowStatus((state) => ({ + ...state, + [id]: data.status, + })); + }; + + const followUser = async (toUserId: string, follow: boolean) => { + const data = await api.post( + follow ? `/users/${toUserId}/follow` : `/users/${toUserId}/unfollow`, + ); + setMyFollowStatus((state) => ({ + ...state, + [toUserId]: data.status, + })); + }; + + const followLabel = (status: FollowStatus) => { + switch (status) { + case "following": + return "Unfollow"; + case "pending": + return "Request Sent"; + case "none": + default: + return "Follow Back"; + } + }; + + return ( + +
    + {requestList.map(({ user, ...follow }) => { + return ( + +
    + + + +
    + + {user.displayName} + + +
    +
    + {theirFollowStatus[follow.id] === "pending" && + myFollowStatus[user.id] === "none"} + +
    +
    +
    + ); + })} +
+
+ ); +} diff --git a/apps/web/src/routes/userDetails.tsx b/apps/web/src/routes/userDetails.tsx index c77fe41f..661fff46 100644 --- a/apps/web/src/routes/userDetails.tsx +++ b/apps/web/src/routes/userDetails.tsx @@ -1,15 +1,17 @@ import type { LoaderFunction } from "react-router-dom"; import { useLoaderData } from "react-router-dom"; +import { useState } from "react"; import Button from "../components/button"; import Layout from "../components/layout"; import TastingListItem from "../components/tastingListItem"; import UserAvatar from "../components/userAvatar"; import { useRequiredAuth } from "../hooks/useAuth"; import api from "../lib/api"; -import type { Tasting, User } from "../types"; +import type { FollowStatus, Tasting, User } from "../types"; -type UserWithStats = User & { +type UserDetails = User & { + followStatus?: FollowStatus; stats: { bottles: number; tastings: number; @@ -18,7 +20,7 @@ type UserWithStats = User & { }; type LoaderData = { - user: UserWithStats; + user: UserDetails; tastingList: Tasting[]; }; @@ -51,6 +53,15 @@ export default function UserDetails() { const { user, tastingList } = useLoaderData() as LoaderData; const { user: currentUser } = useRequiredAuth(); + const [followStatus, setFollowStatus] = useState(user.followStatus); + + const followUser = async (follow: boolean) => { + const data = await api.post( + follow ? `/users/${user.id}/follow` : `/users/${user.id}/unfollow`, + ); + setFollowStatus(data.status); + }; + return (
@@ -85,7 +96,16 @@ export default function UserDetails() {
{user.id !== currentUser.id ? ( <> - + ) : ( <> diff --git a/apps/web/src/types.ts b/apps/web/src/types.ts index 7e2612cb..0b6c1791 100644 --- a/apps/web/src/types.ts +++ b/apps/web/src/types.ts @@ -24,6 +24,9 @@ export type Entity = { region?: string; type: ("brand" | "distiller")[]; totalBottles: number; + totalTastings: number; + createdAt: string; + createdBy?: User; }; export type Bottle = { @@ -34,6 +37,8 @@ export type Bottle = { category?: Category | null; statedAge?: number; totalTastings: number; + createdAt: string; + createdBy?: User; }; export type Edition = { @@ -41,6 +46,18 @@ export type Edition = { name: string; bottle: Bottle; barrel?: number; + createdAt: string; + createdBy?: User; +}; + +export type FollowStatus = "none" | "following" | "pending"; + +export type FollowRequest = { + id: string; + status: FollowStatus; + createdAt: string; + user: User; + followsBack: FollowStatus; }; export type User = { diff --git a/apps/web/tailwind.config.js b/apps/web/tailwind.config.js index 065c0f51..3637fa9b 100644 --- a/apps/web/tailwind.config.js +++ b/apps/web/tailwind.config.js @@ -44,6 +44,20 @@ module.exports = { "100%": { opacity: 0, transform: "translate(-20px, 0)" }, }, }), + + typography: { + DEFAULT: { + css: { + color: "#000", + a: { + color: "#005C58", + "&:hover": { + color: "#005C58", + }, + }, + }, + }, + }, }, }, plugins: [require("@tailwindcss/forms"), require("@tailwindcss/typography")], diff --git a/package.json b/package.json index 6be0fd6b..06f74943 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "db": "dotenv -e .env.local -- pnpm --filter='./apps/api' db", "db:migrate": "dotenv -e .env.local -- pnpm --filter='./apps/api' db:migrate", "db:generate": "dotenv -e .env.local -- pnpm --filter='./apps/api' db:generate", + "load-mocks": "dotenv -e .env.local -- pnpm --filter='./apps/api' load-mocks", "user": "dotenv -e .env.local -- pnpm --filter='./apps/api' user", "typecheck": "pnpm -r --parallel run typecheck", "test": "pnpm -r --stream run test", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2eb48578..d477f6c5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -247,6 +247,9 @@ importers: date-fns: specifier: ^2.30.0 version: 2.30.0 + dayjs: + specifier: ^1.11.7 + version: 1.11.7 framer-motion: specifier: ^10.12.8 version: 10.12.8(react-dom@18.2.0)(react@18.2.0) @@ -5053,6 +5056,10 @@ packages: resolution: {integrity: sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==} dev: false + /dayjs@1.11.7: + resolution: {integrity: sha512-+Yw9U6YO5TQohxLcIkrXBeY73WP3ejHWVvx8XCk3gxvQDCTEmS48ZrSZCKciI7Bhl/uCMyxYtE9UqRILmFphkQ==} + dev: false + /debug@3.2.7(supports-color@5.5.0): resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} peerDependencies: