diff --git a/.dockerignore b/.dockerignore
index 7f2c6dd27..05cbc7845 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -4,3 +4,4 @@
*.md
**/node_modules
**/.next/cache
+data/*
diff --git a/.gitignore b/.gitignore
index 033103d36..71797681d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,3 +2,4 @@
*.DS_Store
node_modules
.env.production
+data/*
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 4e952baa4..01a0d300d 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -17,6 +17,10 @@ variables:
ENABLE_AZURE_POSTGRES: 1
VALUES_FILE: ./.k8s/app.values.yml
+Install:
+ extends: .autodevops_install
+ image: node:12.18.0-alpine3.11
+
Build:
extends: .autodevops_build
variables:
diff --git a/Dockerfile b/Dockerfile
index 2227fd4ae..b05b690b2 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,14 +1,18 @@
-FROM node:14.4-alpine3.11
+FROM node:12.18.0-alpine3.11
WORKDIR /app
COPY package.json yarn.lock ./
-RUN yarn --frozen-lockfile
+RUN apk add --no-cache build-base python --virtual .build-deps \
+ && yarn --production --frozen-lockfile \
+ && apk del .build-deps
COPY next.config.js ./
COPY .env ./.env
COPY .next/ ./.next
+COPY scripts/ ./scripts
+COPY data/ ./data
COPY public/ ./public
USER node
diff --git a/hasura/Dockerfile b/hasura/Dockerfile
index a917f2eb1..c1ad6af03 100644
--- a/hasura/Dockerfile
+++ b/hasura/Dockerfile
@@ -1,4 +1,4 @@
-FROM hasura/graphql-engine:v1.2.1.cli-migrations-v2
+FROM hasura/graphql-engine:v1.2.2.cli-migrations-v2
ENV HASURA_GRAPHQL_ENABLE_TELEMETRY false
COPY ./migrations /hasura-migrations
COPY ./metadata /hasura-metadata
diff --git a/hasura/metadata/tables.yaml b/hasura/metadata/tables.yaml
index 4f6aedc3c..c57eab83e 100644
--- a/hasura/metadata/tables.yaml
+++ b/hasura/metadata/tables.yaml
@@ -98,6 +98,24 @@
headers:
- name: email-secret
value_from_env: ACCOUNT_EMAIL_SECRET
+- table:
+ schema: public
+ name: alert_status
+ array_relationships:
+ - name: alerts
+ using:
+ foreign_key_constraint_on:
+ column: status
+ table:
+ schema: public
+ name: alerts
+- table:
+ schema: public
+ name: alerts
+ object_relationships:
+ - name: source
+ using:
+ foreign_key_constraint_on: repository
- table:
schema: public
name: roles
@@ -122,3 +140,14 @@
columns:
- role
filter: {}
+- table:
+ schema: public
+ name: sources
+ array_relationships:
+ - name: alerts
+ using:
+ foreign_key_constraint_on:
+ column: repository
+ table:
+ schema: public
+ name: alerts
diff --git a/hasura/migrations/1591618615701_alerts/down.sql b/hasura/migrations/1591618615701_alerts/down.sql
new file mode 100644
index 000000000..a084e3530
--- /dev/null
+++ b/hasura/migrations/1591618615701_alerts/down.sql
@@ -0,0 +1,6 @@
+
+DROP TABLE "public"."alerts";
+
+DROP TABLE "public"."sources";
+
+DROP TABLE "public"."alert_status";
diff --git a/hasura/migrations/1591618615701_alerts/up.sql b/hasura/migrations/1591618615701_alerts/up.sql
new file mode 100644
index 000000000..d23c307d5
--- /dev/null
+++ b/hasura/migrations/1591618615701_alerts/up.sql
@@ -0,0 +1,45 @@
+
+CREATE TABLE "public"."alert_status"("name" text NOT NULL DEFAULT 'new', PRIMARY KEY ("name") );
+COMMENT ON TABLE "public"."alert_status" IS E'alert statuses';
+
+INSERT INTO public.alert_status (name) VALUES ('todo');
+INSERT INTO public.alert_status (name) VALUES ('doing');
+INSERT INTO public.alert_status (name) VALUES ('done');
+INSERT INTO public.alert_status (name) VALUES ('rejected');
+
+CREATE TABLE "public"."sources"(
+ "repository" text NOT NULL,
+ "label" text NOT NULL,
+ "tag" text NOT NULL,
+ "created_at" timestamptz NOT NULL DEFAULT now(),
+ PRIMARY KEY ("repository")
+);
+
+COMMENT ON TABLE "public"."sources" IS E'sources are git repository that acts as data sources to track changes';
+
+INSERT INTO public.sources (repository, label, tag) VALUES ('socialgouv/legi-data', 'code du travail', 'v1.12.0');
+INSERT INTO public.sources (repository, label, tag) VALUES ('socialgouv/kali-data', 'conventions collectives', 'v1.64.0');
+
+CREATE TABLE "public"."alerts"(
+ "id" uuid NOT NULL DEFAULT gen_random_uuid(),
+ "info" jsonb NOT NULL,
+ "status" text NOT NULL DEFAULT 'todo',
+ "repository" text NOT NULL,
+ "ref" text NOT NULL,
+ "changes" jsonb NOT NULL,
+ "created_at" timestamptz NULL DEFAULT now(),
+ "updated_at" timestamptz NULL DEFAULT now(),
+ PRIMARY KEY ("id") ,
+ FOREIGN KEY ("status") REFERENCES "public"."alert_status"("name") ON UPDATE restrict ON DELETE restrict,
+ FOREIGN KEY ("repository") REFERENCES "public"."sources"("repository") ON UPDATE restrict ON DELETE cascade);
+
+COMMENT ON TABLE "public"."alerts" IS
+ E'alerts reprensent a change in a text from a source';
+
+CREATE TRIGGER "set_public_alerts_updated_at"
+ BEFORE UPDATE ON public.alerts
+ FOR EACH ROW
+ EXECUTE PROCEDURE trigger_set_timestamp();
+
+COMMENT ON TRIGGER "set_public_alerts_updated_at" ON public.alerts
+ IS 'trigger to set value of column "updated_at" to current timestamp on row update';
diff --git a/package.json b/package.json
index 8a6061d83..47957e752 100644
--- a/package.json
+++ b/package.json
@@ -6,6 +6,7 @@
"dependencies": {
"@hapi/boom": "^9.1.0",
"@hapi/joi": "^17.1.1",
+ "@reach/accordion": "^0.10.3",
"@reach/dialog": "^0.10.3",
"@reach/menu-button": "^0.10.3",
"@reach/visually-hidden": "^0.10.2",
@@ -17,12 +18,14 @@
"@zeit/next-source-maps": "0.0.4-canary.1",
"argon2": "^0.26.2",
"cookie": "^0.4.1",
- "dotenv": "^8.2.0",
+ "diff": "^4.0.2",
"graphql": "^15.0.0",
"http-proxy-middleware": "^1.0.4",
+ "isomorphic-unfetch": "^3.0.0",
"jsonwebtoken": "^8.5.1",
"next": "^9.4.4",
"next-urql": "^0.3.8",
+ "nodegit": "^0.26.5",
"nodemailer": "^6.4.8",
"polished": "^3.6.5",
"react": "^16.13.1",
@@ -30,8 +33,11 @@
"react-hook-form": "^5.7.2",
"react-icons": "^3.10.0",
"react-is": "^16.13.1",
+ "semver": "^7.3.2",
"sentry-testkit": "^3.2.1",
"theme-ui": "^0.3.1",
+ "unist-util-parents": "^1.0.3",
+ "unist-util-select": "^3.0.1",
"urql": "^1.9.8",
"uuid": "^8.1.0",
"wonka": "^4.0.14"
@@ -50,7 +56,12 @@
"scripts": {
"dev": "next dev",
"build": "next build",
+ "prestart": "node scripts/update-alerts.js",
"start": "next start",
+ "alert": " node scripts/update-alerts.js",
+ "alert:dev": "GRAPHQL_ENDPOINT=http://localhost:8080/v1/graphql HASURA_GRAPHQL_ADMIN_SECRET=admin1 node scripts/update-alerts.js",
+ "alert:dump": "GRAPHQL_ENDPOINT=http://localhost:8080/v1/graphql HASURA_GRAPHQL_ADMIN_SECRET=admin1 DUMP=true node scripts/update-alerts.js > data/dump.json",
+ "alert:populate": "GRAPHQL_ENDPOINT=http://localhost:8080/v1/graphql HASURA_GRAPHQL_ADMIN_SECRET=admin1 node scripts/add-alerts.js",
"lint": "eslint src/*",
"test": "jest"
},
diff --git a/scripts/add-alerts.js b/scripts/add-alerts.js
new file mode 100644
index 000000000..1cc8e19b8
--- /dev/null
+++ b/scripts/add-alerts.js
@@ -0,0 +1,30 @@
+const { promises: fs } = require("fs");
+const path = require("path");
+const filename =
+ process.env.DUMP_FILE || path.join(__dirname, "..", "data", "dump.json");
+const { updateSource, insertAlert } = require("./update-alerts");
+
+async function main() {
+ console.log(filename);
+ const fileContent = await fs.readFile(filename);
+ const data = JSON.parse(fileContent);
+
+ for (const result of data) {
+ if (result.changes.length === 0) {
+ console.log(`no update for ${result.repository}`);
+ continue;
+ }
+ const inserts = await Promise.all(
+ result.changes.map((diff) => insertAlert(result.repository, diff))
+ );
+ inserts.forEach((insert) => {
+ const { ref, repository, info } = insert.returning[0];
+ console.log(`insert alert for ${ref} on ${repository} (${info.file})`);
+ });
+ console.log(`create ${inserts.length} alert for ${result.repository}`);
+ const update = await updateSource(result.repository, result.newRef);
+ console.log(`update source ${update.repository} to ${update.tag}`);
+ }
+}
+
+main().catch(console.error);
diff --git a/scripts/lib/ccn-list.js b/scripts/lib/ccn-list.js
new file mode 100644
index 000000000..1de82d3a3
--- /dev/null
+++ b/scripts/lib/ccn-list.js
@@ -0,0 +1,55 @@
+const ccns = [
+ { id: "KALICONT000005635624", num: 16 },
+ { id: "KALICONT000005635234", num: 29 },
+ { id: "KALICONT000005635613", num: 44 },
+ { id: "KALICONT000005635630", num: 86 },
+ { id: "KALICONT000005635184", num: 176 },
+ { id: "KALICONT000005635872", num: 275 },
+ { id: "KALICONT000005635856", num: 292 },
+ { id: "KALICONT000005635407", num: 413 },
+ { id: "KALICONT000005635373", num: 573 },
+ { id: "KALICONT000005635842", num: 650 },
+ { id: "KALICONT000005635617", num: 675 },
+ { id: "KALICONT000005635826", num: 787 },
+ { id: "KALICONT000005635886", num: 843 },
+ { id: "KALICONT000005635953", num: 1043 },
+ { id: "KALICONT000005635191", num: 1090 },
+ { id: "KALICONT000005635409", num: 1147 },
+ { id: "KALICONT000005635418", num: 1266 },
+ { id: "KALICONT000005635405", num: 1351 },
+ { id: "KALICONT000005635653", num: 1404 },
+ { id: "KALICONT000005635444", num: 1480 },
+ { id: "KALICONT000005635594", num: 1483 },
+ { id: "KALICONT000005635173", num: 1486 },
+ { id: "KALICONT000005635596", num: 1501 },
+ { id: "KALICONT000005635421", num: 1505 },
+ { id: "KALICONT000005635435", num: 1516 },
+ { id: "KALICONT000005635870", num: 1517 },
+ { id: "KALICONT000005635177", num: 1518 },
+ { id: "KALICONT000005635413", num: 1527 },
+ { id: "KALICONT000005635221", num: 1596 },
+ { id: "KALICONT000005635220", num: 1597 },
+ { id: "KALICONT000005635871", num: 1606 },
+ { id: "KALICONT000005635918", num: 1672 },
+ { id: "KALICONT000005635467", num: 1702 },
+ { id: "KALICONT000005635685", num: 1740 },
+ { id: "KALICONT000005635534", num: 1979 },
+ { id: "KALICONT000005635528", num: 1996 },
+ { id: "KALICONT000005635550", num: 2098 },
+ { id: "KALICONT000005635792", num: 2111 },
+ { id: "KALICONT000005635780", num: 2120 },
+ { id: "KALICONT000005635557", num: 2148 },
+ { id: "KALICONT000005635085", num: 2216 },
+ { id: "KALICONT000005635813", num: 2264 },
+ { id: "KALICONT000005635807", num: 2395 },
+ { id: "KALICONT000017941839", num: 2420 },
+ { id: "KALICONT000017577652", num: 2511 },
+ { id: "KALICONT000018563755", num: 2596 },
+ { id: "KALICONT000018773893", num: 2609 },
+ { id: "KALICONT000018926209", num: 2614 },
+ { id: "KALICONT000025805800", num: 2941 },
+ { id: "KALICONT000027172335", num: 3043 },
+ { id: "KALICONT000027084096", num: 3127 },
+];
+
+module.exports = { ccns };
diff --git a/scripts/lib/compareTree.js b/scripts/lib/compareTree.js
new file mode 100644
index 000000000..b6d7897b4
--- /dev/null
+++ b/scripts/lib/compareTree.js
@@ -0,0 +1,150 @@
+const parents = require("unist-util-parents");
+const { selectAll } = require("unist-util-select");
+
+const getParents = (node) => {
+ var chain = [];
+ while (node) {
+ node.data.title && chain.unshift(node.data.title);
+ node = node.parent;
+ }
+ return chain;
+};
+
+// find the first parent text id to make legifrance links later
+const getParentTextId = (node) => {
+ let id;
+ node = node.parent;
+ while (node) {
+ if (
+ node.data &&
+ node.data.id &&
+ node.data.id.match(/^(KALI|LEGI)TEXT\d+$/)
+ ) {
+ id = node.data.id;
+ break;
+ }
+ node = node.parent;
+ }
+ return id || null;
+};
+
+// find the root text id to make legifrance links later
+const getRootId = (node) => {
+ let id;
+ while (node) {
+ id = node.data.id;
+ node = node.parent;
+ }
+ return id || null;
+};
+
+const addContext = (node) => ({
+ ...node,
+ parents: getParents(node),
+ textId: getParentTextId(node) || null,
+ rootId: getRootId(node) || null,
+});
+
+// dont include children in final results
+const stripChildren = (node) => node; //({ children, ...props }) => props;
+
+// return diffed articles nodes
+const compareArticles = (tree1, tree2, comparator) => {
+ const parentsTree1 = parents(tree1);
+ const parentsTree2 = parents(tree2);
+
+ // all articles from tree1
+ const articles1 = selectAll("article", parentsTree1).map(addContext);
+ const articles1cids = articles1
+ .map((a) => a && a.data && a.data.cid)
+ .filter(Boolean);
+ // all articles from tree2
+ const articles2 = selectAll("article", parentsTree2).map(addContext);
+ const articles2cids = articles2
+ .map((a) => a && a.data && a.data.cid)
+ .filter(Boolean);
+
+ // new : articles in tree2 not in tree1
+ const newArticles = articles2.filter(
+ (art) => art && art.data && !articles1cids.includes(art.data.cid)
+ );
+ const newArticlesCids = newArticles.map((a) => a.data.cid);
+
+ // supressed: articles in tree1 not in tree2
+ const missingArticles = articles1.filter(
+ (art) => art && art.data && !articles2cids.includes(art.data.cid)
+ );
+
+ // modified : articles with modified texte
+ const modifiedArticles = articles2.filter(
+ (art) =>
+ art &&
+ art.data &&
+ // exclude new articles
+ !newArticlesCids.includes(art.data.cid) &&
+ articles1.find(
+ // same article, different texte
+ (art2) =>
+ art2 &&
+ art2.data &&
+ art2.data.cid === art.data.cid &&
+ comparator(art, art2)
+ )
+ );
+
+ // all sections from tree1
+ const sections1 = selectAll("section", parentsTree1.children).map(addContext);
+
+ const sections1cids = sections1.map((a) => a.data.cid);
+
+ // all sections from tree2
+ const sections2 = selectAll("section", parentsTree2.children).map(addContext);
+ const sections2cids = sections2.map((a) => a.data.cid);
+
+ // new : sections in tree2 not in tree1
+ const newSections = sections2.filter(
+ (section) => !sections1cids.includes(section.data.cid)
+ );
+ const newSectionsCids = newSections.map((a) => a.data.cid);
+
+ // supressed: sections in tree1 not in tree2
+ const missingSections = sections1.filter(
+ (section) => !sections2cids.includes(section.data.cid)
+ );
+
+ // modified : sections with modified texte
+ const modifiedSections = sections2.filter(
+ (section) =>
+ // exclude new sections
+ !newSectionsCids.includes(section.data.cid) &&
+ sections1.find(
+ // same section, different etat
+ (section2) =>
+ section2.data.cid === section.data.cid &&
+ section2.data.etat !== section.data.etat
+ )
+ );
+
+ const changes = {
+ added: [...newSections, ...newArticles].map(stripChildren),
+ removed: [...missingSections, ...missingArticles].map(stripChildren),
+ modified: [
+ ...modifiedSections.map((modif) => ({
+ ...modif,
+ // add the previous version in the result so we can diff later
+ previous: sections1.find(
+ (a) => a.data[idField] === modif.data[idField]
+ ),
+ })),
+ ...modifiedArticles.map((modif) => ({
+ ...modif,
+ // add the previous version in the result so we can diff later
+ previous: articles1.find((a) => a.data.cid === modif.data.cid),
+ })),
+ ].map(stripChildren),
+ };
+
+ return changes;
+};
+
+module.exports = { compareArticles };
diff --git a/scripts/update-alerts.js b/scripts/update-alerts.js
new file mode 100644
index 000000000..716a75efd
--- /dev/null
+++ b/scripts/update-alerts.js
@@ -0,0 +1,279 @@
+const { client } = require("../src/lib/graphqlApiClient.js");
+const path = require("path");
+const nodegit = require("nodegit");
+const semver = require("semver");
+const { ccns } = require("./lib/ccn-list.js");
+const { compareArticles } = require("./lib/compareTree.js");
+
+const sourcesQuery = `
+query getSources {
+ sources {
+ repository
+ tag
+ }
+}
+`;
+
+const insertAlertsMutation = `
+mutation insert_alerts($data: alerts_insert_input!) {
+ alert: insert_alerts(objects: [$data]) {
+ returning {
+ ref,
+ repository,
+ info
+ }
+ }
+}
+`;
+
+const updateSourceMutation = `
+mutation updateSource($repository: String!, $tag: String!){
+ source: update_sources_by_pk(
+ _set:{
+ tag: $tag
+ },
+ pk_columns: {
+ repository: $repository
+ }
+ ){
+ repository, tag
+ }
+}
+`;
+
+function getFileFilter(repository) {
+ switch (repository) {
+ case "socialgouv/legi-data":
+ // only code-du-travail
+ return (path) => /LEGITEXT000006072050\.json$/.test(path);
+ case "socialgouv/kali-data":
+ // only a ccn matching our list
+ return (path) => ccns.some((ccn) => new RegExp(ccn.id).test(path));
+ default:
+ return () => true;
+ }
+}
+
+function getFileComparator(repository) {
+ switch (repository) {
+ case "socialgouv/legi-data":
+ // only code-du-travail
+ return (art1, art2) =>
+ art1.data.texte !== art2.data.texte ||
+ art1.data.etat !== art2.data.etat ||
+ art1.data.nota !== art2.data.nota;
+ case "socialgouv/kali-data":
+ // only a ccn matching our list
+ return (art1, art2) =>
+ art1.data.content !== art2.data.content ||
+ art1.data.etat !== art2.data.etat;
+ default:
+ return () => true;
+ }
+}
+
+function getFilename(patche) {
+ return patche.newFile().path();
+}
+
+async function getSources() {
+ const result = await client.query(sourcesQuery).toPromise();
+ if (result.error) {
+ console.error(result.error);
+ throw new Error("getSources");
+ }
+ return result.data.sources;
+}
+
+async function insertAlert(repository, changes) {
+ const data = {
+ repository,
+ info: {
+ num: changes.num,
+ title: changes.title,
+ id: changes.id,
+ file: changes.file,
+ },
+ ref: changes.ref,
+ changes: {
+ added: changes.added,
+ removed: changes.removed,
+ modified: changes.modified,
+ },
+ };
+ const result = await client
+ .mutation(insertAlertsMutation, { data })
+ .toPromise();
+ if (result.error) {
+ console.error(result.error);
+ throw new Error("insertAlert");
+ }
+ return result.data.alert;
+}
+
+async function updateSource(repository, tag) {
+ const result = await client
+ .mutation(updateSourceMutation, {
+ repository,
+ tag,
+ })
+ .toPromise();
+
+ if (result.error) {
+ console.error(result.error);
+ throw new Error("updateSource");
+ }
+ return result.data.source;
+}
+
+async function openRepo({ repository }) {
+ const [org, repositoryName] = repository.split("/");
+ const localPath = path.join(__dirname, "..", "data", repositoryName);
+ let repo;
+ try {
+ repo = await nodegit.Repository.open(localPath);
+ await repo.checkoutBranch("master");
+ await repo.mergeBranches("master", "origin/master");
+ } catch (err) {
+ repo = await nodegit.Clone(
+ `git://github.com/${org}/${repositoryName}`,
+ localPath
+ );
+ }
+ return repo;
+}
+
+async function getNewerTagsFromRepo(repo, tag) {
+ const tags = await nodegit.Tag.list(repo);
+ return await Promise.all(
+ tags
+ .flatMap((t) => {
+ if (!semver.valid(t)) {
+ return [];
+ }
+ if (semver.lt(t, tag)) {
+ return [];
+ }
+ return t;
+ })
+ .sort((a, b) => (semver.lt(a, b) ? -1 : 1))
+ .map(async (tag) => {
+ const reference = await repo.getReference(tag);
+ const targetRef = await reference.peel(nodegit.Object.TYPE.COMMIT);
+ const commit = await repo.getCommit(targetRef);
+ return {
+ ref: tag,
+ commit,
+ };
+ })
+ );
+}
+
+async function getDiffFromTags(tags, id) {
+ let [previousTag] = tags;
+ const [, ...newTags] = tags;
+ const changes = [];
+ const fileFilter = getFileFilter(id);
+
+ for (const tag of newTags) {
+ const { commit: previousCommit } = previousTag;
+ const { commit } = tag;
+ const [prevTree, currTree] = await Promise.all([
+ previousCommit.getTree(),
+ commit.getTree(),
+ ]);
+
+ const patches = await currTree
+ .diff(prevTree)
+ .then((diff) => diff.patches());
+
+ const files = patches.map(getFilename).filter(fileFilter);
+
+ if (files.length > 0) {
+ const fileChanges = await Promise.all(
+ files.map((file) =>
+ getFileDiffFromTrees(file, currTree, prevTree, getFileComparator(id))
+ )
+ );
+ fileChanges
+ .filter(
+ (file) =>
+ file.modified.length > 0 ||
+ file.removed.length > 0 ||
+ file.added.length > 0
+ )
+ .forEach((change) => {
+ changes.push({ ref: tag.ref, ...change });
+ });
+ }
+ previousTag = tag;
+ }
+ return changes;
+}
+
+async function getFileDiffFromTrees(
+ filePath,
+ currGitTree,
+ prevGitTree,
+ compareFn
+) {
+ const [currentFile, prevFile] = await Promise.all([
+ currGitTree.getEntry(filePath).then((entry) => entry.getBlob()),
+ prevGitTree.getEntry(filePath).then((entry) => entry.getBlob()),
+ ]);
+ const currTree = JSON.parse(currentFile.toString());
+ const prevTree = JSON.parse(prevFile.toString());
+ return {
+ file: filePath,
+ id: currTree.data.id,
+ num: currTree.data.num,
+ title: currTree.data.title,
+ ...compareArticles(prevTree, currTree, compareFn),
+ };
+}
+
+async function main() {
+ const sources = await getSources();
+ const results = [];
+ for (const source of sources) {
+ const repo = await openRepo(source);
+ const tags = await getNewerTagsFromRepo(repo, source.tag);
+ const diffs = await getDiffFromTags(tags, source.repository);
+ const [lastTag] = tags.slice(-1);
+
+ results.push({
+ repository: source.repository,
+ changes: diffs,
+ newRef: lastTag.ref,
+ });
+ }
+
+ if (process.env.DUMP) {
+ console.log(JSON.stringify(results, 0, 2));
+ } else {
+ for (const result of results) {
+ if (result.changes.length === 0) {
+ console.log(`no update for ${result.repository}`);
+ continue;
+ }
+ const inserts = await Promise.all(
+ result.changes.map((diff) => insertAlert(result.repository, diff))
+ );
+ inserts.forEach((insert) => {
+ const { ref, repository, info } = insert.returning[0];
+ console.log(`insert alert for ${ref} on ${repository} (${info.file})`);
+ });
+ console.log(`create ${inserts.length} alert for ${result.repository}`);
+ const update = await updateSource(result.repository, result.newRef);
+ console.log(`update source ${update.repository} to ${update.tag}`);
+ }
+ }
+}
+
+main().catch(console.error);
+
+module.exports = {
+ getSources,
+ insertAlert,
+ updateSource,
+};
diff --git a/src/components/alerts/AlertTitle.js b/src/components/alerts/AlertTitle.js
new file mode 100644
index 000000000..c682750f0
--- /dev/null
+++ b/src/components/alerts/AlertTitle.js
@@ -0,0 +1,18 @@
+/** @jsx jsx */
+
+import { jsx, Flex, Box } from "theme-ui";
+import PropTypes from "prop-types";
+import { AlertStatus } from "./Status";
+
+export function AlertTitle({ alertId, ...props }) {
+ return (
+
+
+
+
+ );
+}
+
+AlertTitle.propTypes = {
+ alertId: PropTypes.string.isRequired,
+};
diff --git a/src/components/alerts/Status.js b/src/components/alerts/Status.js
new file mode 100644
index 000000000..b80905dc5
--- /dev/null
+++ b/src/components/alerts/Status.js
@@ -0,0 +1,45 @@
+/** @jsx jsx */
+
+import { IoIosCheckmark, IoIosClose } from "react-icons/io";
+import { MenuButton, MenuItem } from "../button";
+import { jsx } from "theme-ui";
+import PropTypes from "prop-types";
+import { useMutation } from "urql";
+
+export const alertMutation = `
+mutation updateAlertStatus($id:uuid!, $status:String!) {
+ update_alerts_by_pk(
+ pk_columns: {
+ id: $id
+ }
+ _set: { status: $status }
+ ){
+ __typename
+ }
+}
+`;
+
+export function AlertStatus({ alertId }) {
+ const [, executeUpdate] = useMutation(alertMutation);
+ function updateStatus(status) {
+ console.log("update statys", alertId, status);
+ executeUpdate({ id: alertId, status });
+ }
+ return (
+
+
+
+
+
+ );
+}
+AlertStatus.propTypes = {
+ alertId: PropTypes.string.isRequired,
+};
diff --git a/src/components/button/index.js b/src/components/button/index.js
index e9e54e8c8..823f75f51 100644
--- a/src/components/button/index.js
+++ b/src/components/button/index.js
@@ -13,7 +13,13 @@ import {
MenuList,
MenuItem as ReachMenuItem,
} from "@reach/menu-button";
-import { IoMdMore } from "react-icons/io";
+
+import {
+ AccordionButton as ReachAccordionButton,
+ useAccordionItemContext,
+} from "@reach/accordion";
+
+import { IoMdMore, IoIosArrowForward, IoIosArrowDown } from "react-icons/io";
const buttonPropTypes = {
variant: PropTypes.oneOf(["secondary", "primary", "link"]),
@@ -188,3 +194,28 @@ export function MenuItem(props) {
/>
);
}
+
+export function AccordionButton({ children, ...props }) {
+ return (
+
+
+ {children}
+
+ );
+}
+
+export function ExpandedIcon() {
+ const { isExpanded } = useAccordionItemContext();
+ return isExpanded ? : ;
+}
diff --git a/src/components/changes/ChangeGroup.js b/src/components/changes/ChangeGroup.js
new file mode 100644
index 000000000..8e6610d69
--- /dev/null
+++ b/src/components/changes/ChangeGroup.js
@@ -0,0 +1,27 @@
+import React from "react";
+import PropTypes from "prop-types";
+import { AccordionButton } from "src/components/button";
+import { AccordionItem, AccordionPanel } from "@reach/accordion";
+
+export const ChangesGroup = ({ changes, label, renderChange }) => {
+ return changes.length > 0 ? (
+
+ {label}
+
+ {changes.map(renderChange)}
+
+
+ ) : null;
+};
+
+ChangesGroup.propTypes = {
+ label: PropTypes.string.isRequired,
+ renderChange: PropTypes.func.isRequired,
+ changes: PropTypes.arrayOf(
+ PropTypes.shape({
+ added: PropTypes.object,
+ removed: PropTypes.object,
+ modified: PropTypes.object,
+ })
+ ),
+};
diff --git a/src/components/changes/ViewDiff.js b/src/components/changes/ViewDiff.js
new file mode 100644
index 000000000..145354730
--- /dev/null
+++ b/src/components/changes/ViewDiff.js
@@ -0,0 +1,69 @@
+// adapted from https://github.com/davidmason/react-stylable-diff/blob/master/lib/react-diff.js
+/** @jsx jsx */
+
+import { useState, useMemo } from "react";
+import { jsx } from "theme-ui";
+var jsdiff = require("diff");
+
+const fnMap = {
+ chars: jsdiff.diffChars,
+ words: jsdiff.diffWords,
+ sentences: jsdiff.diffSentences,
+ json: jsdiff.diffJson,
+};
+
+export const ViewDiff = ({ sx, type, inputA, inputB }) => {
+ const [mode, setMode] = useState(type);
+ const diff = fnMap[mode](inputA, inputB);
+
+ const groupName = useMemo(() => Math.random());
+
+ const result = diff.map((part, index) => {
+ if (part.added) {
+ return (
+
+ {part.value}
+
+ );
+ }
+ if (part.removed) {
+ return (
+
+ {part.value}
+
+ );
+ }
+ return {part.value};
+ });
+ return (
+
+ );
+};
+
+ViewDiff.defaultProps = {
+ inputA: "",
+ inputB: "",
+ type: "chars",
+ className: "Difference",
+};
diff --git a/src/components/changes/index.js b/src/components/changes/index.js
new file mode 100644
index 000000000..d732ce283
--- /dev/null
+++ b/src/components/changes/index.js
@@ -0,0 +1,85 @@
+/** @jsx jsx */
+import { jsx, Badge, Card } from "theme-ui";
+import { ViewDiff } from "./ViewDiff";
+import { Collapsible } from "../collapsible";
+import PropTypes from "prop-types";
+
+export function DiffChange({ change, repository }) {
+ const { data, previous } = change;
+ const textFieldname = /legi-data/.test(repository) ? "texte" : "content";
+ const content = data[textFieldname] || "";
+ const previousContent = previous?.data[textFieldname] || "";
+ const showDiff = previous && content !== previousContent;
+ const showNotaDiff = previous && previous.data.nota !== data.nota;
+ return (
+
+ Article {data.num}{" "}
+ {previous?.data.etat && previous?.data.etat !== data.etat && (
+ <>
+
+ {previous.data.etat}
+ {" "}
+ ›{" "}
+ >
+ )}
+
+ {data.etat}
+
+ {showDiff && (
+
+
+
+
+
+ )}
+ {showNotaDiff && (
+
+
+
+
+
+ )}
+
+ );
+}
+
+DiffChange.propTypes = {
+ repository: PropTypes.string.isRequired,
+ change: PropTypes.object.isRequired,
+};
+
+function getBadgeColor(etat) {
+ switch (etat) {
+ case "VIGUEUR":
+ return "positive";
+ case "MOIFIE":
+ return "caution";
+ case "ABROGE":
+ case "ABROGE_DIFF":
+ return "critical";
+ default:
+ return "info";
+ }
+}
diff --git a/src/components/collapsible/index.js b/src/components/collapsible/index.js
new file mode 100644
index 000000000..8ddb5e8dc
--- /dev/null
+++ b/src/components/collapsible/index.js
@@ -0,0 +1,16 @@
+import { Button } from "../button";
+
+import React, { useState } from "react";
+import { IoMdGitNetwork } from "react-icons/io";
+
+export function Collapsible({ label, children, ...props }) {
+ const [isVisible, setVisible] = useState(false);
+ return (
+
+
+ {isVisible && children}
+
+ );
+}
diff --git a/src/components/layout/Nav.js b/src/components/layout/Nav.js
index 9d908335e..9c6c3c88c 100644
--- a/src/components/layout/Nav.js
+++ b/src/components/layout/Nav.js
@@ -1,17 +1,40 @@
-import { jsx, Box, NavLink, Text } from "theme-ui";
+/** @jsx jsx */
+
+import { jsx, Box, NavLink, Text, Badge } from "theme-ui";
import { useAuth } from "src/hooks/useAuth";
import Link from "next/link";
import { Li, List } from "../list";
+import { useQuery } from "urql";
+import { useMemo } from "react";
+
+const getSourcesQuery = `
+query getAlerts{
+ sources {
+ repository,
+ label,
+ alerts: alerts_aggregate(where: {status: {_eq: "todo"}}) {
+ aggregate {
+ count
+ }
+ }
+ }
+}
+`;
-/** @jsx jsx */
export function Nav() {
const { user } = useAuth();
const isAdmin = user?.roles.some(({ role }) => role === "admin");
-
+ // https://formidable.com/open-source/urql/docs/basics/document-caching/#adding-typenames
+ const context = useMemo(
+ () => ({ additionalTypenames: ["alerts", "sources"] }),
+ []
+ );
+ const [result] = useQuery({ query: getSourcesQuery, context });
+ const { fetching, data } = result;
return (
- Navigation
+ Utilisateurs
{isAdmin && (
@@ -21,6 +44,28 @@ export function Nav() {
)}
+ Alertes
+ {!fetching && (
+
+ {data.sources.map((source) => (
+
+
+ {source.label}
+
+ {" "}
+ {source.alerts.aggregate.count > 0 && (
+
+ {source.alerts.aggregate.count}
+
+ )}
+
+ ))}
+
+ )}
);
diff --git a/src/components/tabs/index.js b/src/components/tabs/index.js
new file mode 100644
index 000000000..99b1c177a
--- /dev/null
+++ b/src/components/tabs/index.js
@@ -0,0 +1,50 @@
+/** @jsx jsx */
+import { jsx } from "theme-ui";
+import PropTypes from "prop-types";
+
+export function Tabs(props) {
+ return (
+
+ );
+}
+
+export function TabItem({ selected, controls, ...props }) {
+ return (
+
+ );
+}
+TabItem.propTypes = {
+ selected: PropTypes.bool,
+ controls: PropTypes.string.isRequired,
+};
+TabItem.defaultProps = {
+ selected: false,
+};
diff --git a/src/lib/graphqlApiClient.js b/src/lib/graphqlApiClient.js
index d1f40a76c..c25f4bee3 100644
--- a/src/lib/graphqlApiClient.js
+++ b/src/lib/graphqlApiClient.js
@@ -1,9 +1,14 @@
-import { createClient } from "urql";
+/**
+ * using require syntax here because graphqlClient is alos used
+ * within the nodejs scripts
+ */
+require("isomorphic-unfetch");
+const { createClient } = require("urql");
const HASURA_GRAPHQL_ADMIN_SECRET = process.env.HASURA_GRAPHQL_ADMIN_SECRET;
const HASURA_GRAPHQL_ENDPOINT = process.env.GRAPHQL_ENDPOINT;
-export const client = new createClient({
+const client = createClient({
url: HASURA_GRAPHQL_ENDPOINT,
requestPolicy: "network-only",
fetchOptions: {
@@ -13,3 +18,4 @@ export const client = new createClient({
},
},
});
+module.exports = { client };
diff --git a/src/models.js b/src/models.js
new file mode 100644
index 000000000..786580024
--- /dev/null
+++ b/src/models.js
@@ -0,0 +1,10 @@
+export const statusLabels = {
+ todo: "À traiter",
+ doing: "En cours de traitement",
+ done: "Traités",
+ rejected: "Rejetés",
+};
+
+export function getStatusLabel(status) {
+ return statusLabels[status] || status;
+}
diff --git a/src/pages/_app.js b/src/pages/_app.js
index 304d568ac..84414355c 100644
--- a/src/pages/_app.js
+++ b/src/pages/_app.js
@@ -6,6 +6,7 @@ import { theme } from "src/theme";
import { ThemeProvider } from "theme-ui";
import "@reach/menu-button/styles.css";
import "@reach/dialog/styles.css";
+import "@reach/accordion/styles.css";
Sentry.init({
enabled: process.env.NODE_ENV === "production",
diff --git a/src/pages/alerts/[repo].js b/src/pages/alerts/[repo].js
new file mode 100644
index 000000000..229ff7328
--- /dev/null
+++ b/src/pages/alerts/[repo].js
@@ -0,0 +1,144 @@
+/** @jsx jsx */
+
+import Link from "next/link";
+import { withCustomUrqlClient } from "src/hoc/CustomUrqlClient";
+import { Layout } from "src/components/layout/auth.layout";
+import { withAuthProvider } from "src/lib/auth";
+import { jsx, Message, NavLink, Container, Divider } from "theme-ui";
+import { useRouter } from "next/router";
+import { useQuery } from "urql";
+import { useState, useEffect, useMemo } from "react";
+import { Accordion } from "@reach/accordion";
+import { Tabs, TabItem } from "src/components/tabs";
+import { ChangesGroup } from "src/components/changes/ChangeGroup";
+import { DiffChange } from "src/components/changes";
+import { AlertTitle } from "src/components/alerts/AlertTitle";
+import { getStatusLabel } from "src/models";
+
+const getAlertQuery = `
+query getAlerts($status: String!, $repository: String!) {
+ statuses: alert_status {
+ name
+ alerts: alerts_aggregate(where: {
+ repository: {_eq: $repository }
+ }) {
+ aggregate {
+ count
+ }
+ __typename
+ }
+ }
+ alerts(where: {
+ _and: [
+ {status: {_eq: $status}},
+ {repository: {_eq: $repository}},
+ ]
+ }) {
+ id
+ ref
+ info
+ changes
+ status
+ created_at
+ __typename
+ }
+}
+`;
+
+export function AlertPage() {
+ const router = useRouter();
+ const [, initialHash = "todo"] = router.asPath.split("#");
+ const [hash, setHash] = useState(initialHash);
+ // https://formidable.com/open-source/urql/docs/basics/document-caching/#adding-typenames
+ const context = useMemo(() => ({ additionalTypenames: ["alerts"] }), []);
+
+ const repository = router.query.repo.replace(/–/g, "/");
+ const [result] = useQuery({
+ query: getAlertQuery,
+ variables: { repository, status: hash },
+ context,
+ });
+
+ useEffect(() => {
+ function onHashChange(url) {
+ const [, hash = "todo"] = url.split("#");
+ setHash(hash);
+ }
+
+ router.events.on("hashChangeComplete", onHashChange);
+ return function () {
+ router.events.off("hashChangeComplete", onHashChange);
+ };
+ });
+
+ const { fetching, error, data } = result;
+ if (fetching) {
+ return Chargement...
;
+ }
+ if (error) {
+ return (
+
+ {JSON.stringify(error, 0, 2)}
+
+ );
+ }
+ const { statuses, alerts } = data;
+
+ function renderChange(change, key) {
+ return ;
+ }
+
+ return (
+
+
+ {statuses.map((status) => (
+
+
+
+ {getStatusLabel(status.name)} ({status.alerts.aggregate.count})
+
+
+
+ ))}
+
+ {alerts.map((alert) => (
+
+
+ IDCC{alert.info.num} -{" "}
+ {new Date(alert.created_at).toLocaleDateString()} ({alert.ref})
+
+
+ {alert.changes.added.length > 0 && (
+
+ renderChange(changes, `${alert.ref}-added-${i}`)
+ }
+ />
+ )}
+ {alert.changes.added.length > 0 &&
+ alert.changes.modified.length > 0 && }
+
+ renderChange(changes, `${alert.ref}-modified-${i}`)
+ }
+ />
+ {alert.changes.removed.length > 0 && }
+
+ renderChange(changes, `${alert.ref}-removed-${i}`)
+ }
+ />
+
+
+ ))}
+
+ );
+}
+
+export default withCustomUrqlClient(withAuthProvider(AlertPage));
diff --git a/src/theme.js b/src/theme.js
index 53f624edc..e3c8d87b8 100644
--- a/src/theme.js
+++ b/src/theme.js
@@ -1,12 +1,18 @@
import { rgba, darken, transparentize } from "polished";
export const theme = {
+ fonts: {
+ body: "muli",
+ heading: "muli",
+ monospace: "monospace",
+ },
sizes: {
container: 1440,
normal: "xsmall",
small: "xxsmall",
},
fontSizes: {
+ 0: "0.8rem",
xsmall: "0.8rem",
small: "0.9rem",
medium: "1rem",
@@ -15,11 +21,13 @@ export const theme = {
xxlarge: "3.2rem",
icons: "1.5rem",
},
+ // fontSizes: [12, 14, 16, 20, 24, 32, 48, 64],
fontWeights: {
body: 300,
regular: 400,
heading: 600,
semibold: 600,
+ bold: 600,
},
lineHeights: {
body: 1.625,
@@ -69,6 +77,7 @@ export const theme = {
radii: {
small: "4px",
large: "8px",
+ xlarge: "16px",
},
breakpoints: ["40rem", "56rem", "64rem"],
styles: {
@@ -131,15 +140,25 @@ export const theme = {
primary: {
bg: "primary",
color: "white",
- fontSize: "medium",
px: "xxsmall",
},
secondary: {
bg: "secondary",
color: "white",
- fontSize: "medium",
px: "xxsmall",
},
+ outline: {
+ color: "primary",
+ bg: "transparent",
+ boxShadow: "inset 0 0 0 1px",
+ },
+ circle: {
+ bg: "accent",
+ borderRadius: "xlarge",
+ px: "5px",
+ py: "3px",
+ lineHeight: 1,
+ },
},
forms: {
label: {
diff --git a/yarn.lock b/yarn.lock
index f8ca8c5db..c8a3f9e9a 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1500,6 +1500,16 @@
dependencies:
safe-buffer "^5.1.2"
+"@reach/accordion@^0.10.3":
+ version "0.10.3"
+ resolved "https://registry.yarnpkg.com/@reach/accordion/-/accordion-0.10.3.tgz#6be590b6f8468a42f5727d1ff5ea03f7b36eb8be"
+ integrity sha512-GzRCJUPeDTGUdo+TMdwOFTTKc0GubkOEdBTQcOjKKMcLHxpOfZTx+hvkNREnXuqAyylyOfhxBKnuMWGS45+Weg==
+ dependencies:
+ "@reach/auto-id" "^0.10.3"
+ "@reach/descendants" "^0.10.3"
+ "@reach/utils" "^0.10.3"
+ tslib "^1.11.2"
+
"@reach/auto-id@^0.10.3":
version "0.10.3"
resolved "https://registry.yarnpkg.com/@reach/auto-id/-/auto-id-0.10.3.tgz#d2b6fe3ccb81b0fb44dc8bd3aca567c94ac11f5e"
@@ -2506,6 +2516,11 @@ arrify@^2.0.1:
resolved "https://registry.yarnpkg.com/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa"
integrity sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==
+asap@~2.0.3:
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
+ integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=
+
asn1.js@^4.0.0:
version "4.10.1"
resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0"
@@ -2785,6 +2800,14 @@ bindings@^1.5.0:
dependencies:
file-uri-to-path "1.0.0"
+bl@^1.0.0:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.2.tgz#a160911717103c07410cef63ef51b397c025af9c"
+ integrity sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==
+ dependencies:
+ readable-stream "^2.3.5"
+ safe-buffer "^5.1.1"
+
bluebird@^3.5.5:
version "3.7.2"
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f"
@@ -2939,11 +2962,29 @@ bser@2.1.1:
dependencies:
node-int64 "^0.4.0"
+buffer-alloc-unsafe@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0"
+ integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==
+
+buffer-alloc@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec"
+ integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==
+ dependencies:
+ buffer-alloc-unsafe "^1.1.0"
+ buffer-fill "^1.0.0"
+
buffer-equal-constant-time@1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819"
integrity sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=
+buffer-fill@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c"
+ integrity sha1-+PeLdniYiO858gXNY39o5wISKyw=
+
buffer-from@^1.0.0, buffer-from@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
@@ -3202,7 +3243,7 @@ chokidar@^3.3.0, chokidar@^3.4.0:
optionalDependencies:
fsevents "~2.1.2"
-chownr@^1.1.1, chownr@^1.1.2:
+chownr@^1.0.1, chownr@^1.1.1, chownr@^1.1.2:
version "1.1.4"
resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b"
integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==
@@ -3684,6 +3725,11 @@ css-select@^2.0.0:
domutils "^1.7.0"
nth-check "^1.0.2"
+css-selector-parser@^1.0.0:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/css-selector-parser/-/css-selector-parser-1.4.1.tgz#03f9cb8a81c3e5ab2c51684557d5aaf6d2569759"
+ integrity sha512-HYPSb7y/Z7BNDCOrakL4raGO2zltZkbeXyAd6Tg9obzix6QhzxCotdBl6VT0Dv4vZfJGVz3WL/xaEI9Ly3ul0g==
+
css-tree@1.0.0-alpha.37:
version "1.0.0-alpha.37"
resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.37.tgz#98bebd62c4c1d9f960ec340cf9f7522e30709a22"
@@ -4011,6 +4057,11 @@ diff-sequences@^26.0.0:
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-26.0.0.tgz#0760059a5c287637b842bd7085311db7060e88a6"
integrity sha512-JC/eHYEC3aSS0vZGjuoc4vHA0yAQTzhQQldXMeMF+JlxLGJlCO38Gma82NV9gk1jGFz8mDzUMeaKXvjRRdJ2dg==
+diff@^4.0.2:
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
+ integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==
+
diffie-hellman@^5.0.0:
version "5.0.3"
resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875"
@@ -4110,11 +4161,6 @@ dot-prop@^5.2.0:
dependencies:
is-obj "^2.0.0"
-dotenv@^8.2.0:
- version "8.2.0"
- resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.2.0.tgz#97e619259ada750eea3e4ea3e26bceea5424b16a"
- integrity sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==
-
duplexify@^3.4.2, duplexify@^3.6.0:
version "3.7.1"
resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309"
@@ -4249,7 +4295,7 @@ es-to-primitive@^1.2.1:
is-date-object "^1.0.1"
is-symbol "^1.0.2"
-es5-ext@^0.10.35, es5-ext@^0.10.50:
+es5-ext@^0.10.35, es5-ext@^0.10.46, es5-ext@^0.10.50:
version "0.10.53"
resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.53.tgz#93c5a3acfdbef275220ad72644ad02ee18368de1"
integrity sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==
@@ -4258,7 +4304,7 @@ es5-ext@^0.10.35, es5-ext@^0.10.50:
es6-symbol "~3.1.3"
next-tick "~1.0.0"
-es6-iterator@2.0.3, es6-iterator@~2.0.3:
+es6-iterator@2.0.3, es6-iterator@^2.0.3, es6-iterator@~2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7"
integrity sha1-p96IkUGgWpSwhUQDstCg+/qY87c=
@@ -4275,6 +4321,16 @@ es6-symbol@^3.1.1, es6-symbol@~3.1.3:
d "^1.0.1"
ext "^1.1.2"
+es6-weak-map@^2.0.0:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.3.tgz#b6da1f16cc2cc0d9be43e6bdbfc5e7dfcdf31d53"
+ integrity sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==
+ dependencies:
+ d "1"
+ es5-ext "^0.10.46"
+ es6-iterator "^2.0.3"
+ es6-symbol "^3.1.1"
+
escape-html@~1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
@@ -4914,6 +4970,20 @@ from2@^2.1.0:
inherits "^2.0.1"
readable-stream "^2.0.0"
+fs-constants@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad"
+ integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==
+
+fs-extra@^7.0.0:
+ version "7.0.1"
+ resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9"
+ integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==
+ dependencies:
+ graceful-fs "^4.1.2"
+ jsonfile "^4.0.0"
+ universalify "^0.1.0"
+
fs-minipass@^1.2.5:
version "1.2.7"
resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7"
@@ -5062,7 +5132,7 @@ glob-to-regexp@^0.4.1:
resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e"
integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==
-glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6:
+glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6:
version "7.1.6"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==
@@ -5093,7 +5163,7 @@ globals@^12.1.0:
dependencies:
type-fest "^0.8.1"
-graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.2.2, graceful-fs@^4.2.4:
+graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.6, graceful-fs@^4.2.2, graceful-fs@^4.2.4:
version "4.2.4"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb"
integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==
@@ -5818,6 +5888,14 @@ isobject@^3.0.0, isobject@^3.0.1:
resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8=
+isomorphic-unfetch@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/isomorphic-unfetch/-/isomorphic-unfetch-3.0.0.tgz#de6d80abde487b17de2c400a7ef9e5ecc2efb362"
+ integrity sha512-V0tmJSYfkKokZ5mgl0cmfQMTb7MLHsBMngTkbLY0eXvKqiVRRoZP04Ly+KhKrJfKtzC9E6Pp15Jo+bwh7Vi2XQ==
+ dependencies:
+ node-fetch "^2.2.0"
+ unfetch "^4.0.0"
+
isstream@~0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
@@ -6327,6 +6405,13 @@ json5@^2.1.0, json5@^2.1.2:
dependencies:
minimist "^1.2.5"
+jsonfile@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb"
+ integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=
+ optionalDependencies:
+ graceful-fs "^4.1.6"
+
jsonparse@^1.2.0:
version "1.3.1"
resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280"
@@ -6989,7 +7074,7 @@ mute-stream@0.0.8:
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d"
integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==
-nan@^2.12.1:
+nan@^2.12.1, nan@^2.14.0:
version "2.14.1"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.1.tgz#d7be34dfa3105b91494c3147089315eff8874b01"
integrity sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==
@@ -7024,9 +7109,9 @@ natural-compare@^1.4.0:
integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=
needle@^2.2.1:
- version "2.4.1"
- resolved "https://registry.yarnpkg.com/needle/-/needle-2.4.1.tgz#14af48732463d7475696f937626b1b993247a56a"
- integrity sha512-x/gi6ijr4B7fwl6WYL9FwlCvRQKGlUNvnceho8wxkwXqN8jvVmmmATTmZPRRG7b/yC1eode26C2HO9jl78Du9g==
+ version "2.5.0"
+ resolved "https://registry.yarnpkg.com/needle/-/needle-2.5.0.tgz#e6fc4b3cc6c25caed7554bd613a5cf0bac8c31c0"
+ integrity sha512-o/qITSDR0JCyCKEQ1/1bnUXMmznxabbwi/Y4WwJElf+evwJNFNwIDMCCt5IigFVxgeGBJESLohGtIS9gEzo1fA==
dependencies:
debug "^3.2.6"
iconv-lite "^0.4.4"
@@ -7118,15 +7203,32 @@ nice-try@^1.0.4:
integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==
node-addon-api@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-2.0.0.tgz#f9afb8d777a91525244b01775ea0ddbe1125483b"
- integrity sha512-ASCL5U13as7HhOExbT6OlWJJUV/lLzL2voOSP1UVehpRD8FbSrSDjfScK/KwAvVTI5AS6r4VwbOMlIqtvRidnA==
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-2.0.1.tgz#4fd0931bf6d7e48b219ff3e6abc73cbb0252b7a3"
+ integrity sha512-2WVfwRfIr1AVn3dRq4yRc2Hn35ND+mPJH6inC6bjpYCZVrpXPB4j3T6i//OGVfqVsR1t/X/axRulDsheq4F0LQ==
-node-fetch@2.6.0, node-fetch@^2.6.0:
+node-fetch@2.6.0, node-fetch@^2.2.0, node-fetch@^2.6.0:
version "2.6.0"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd"
integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==
+node-gyp@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-4.0.0.tgz#972654af4e5dd0cd2a19081b4b46fe0442ba6f45"
+ integrity sha512-2XiryJ8sICNo6ej8d0idXDEMKfVfFK7kekGCtJAuelGsYHQxhj13KTf95swTCN2dZ/4lTfZ84Fu31jqJEEgjWA==
+ dependencies:
+ glob "^7.0.3"
+ graceful-fs "^4.1.2"
+ mkdirp "^0.5.0"
+ nopt "2 || 3"
+ npmlog "0 || 1 || 2 || 3 || 4"
+ osenv "0"
+ request "^2.87.0"
+ rimraf "2"
+ semver "~5.3.0"
+ tar "^4.4.8"
+ which "1"
+
node-int64@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b"
@@ -7178,6 +7280,22 @@ node-notifier@^7.0.0:
uuid "^7.0.3"
which "^2.0.2"
+node-pre-gyp@^0.13.0:
+ version "0.13.0"
+ resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.13.0.tgz#df9ab7b68dd6498137717838e4f92a33fc9daa42"
+ integrity sha512-Md1D3xnEne8b/HGVQkZZwV27WUi1ZRuZBij24TNaZwUPU3ZAFtvT6xxJGaUVillfmMKnn5oD1HoGsp2Ftik7SQ==
+ dependencies:
+ detect-libc "^1.0.2"
+ mkdirp "^0.5.1"
+ needle "^2.2.1"
+ nopt "^4.0.1"
+ npm-packlist "^1.1.6"
+ npmlog "^4.0.2"
+ rc "^1.2.7"
+ rimraf "^2.6.1"
+ semver "^5.3.0"
+ tar "^4"
+
node-pre-gyp@^0.14.0:
version "0.14.0"
resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.14.0.tgz#9a0596533b877289bcad4e143982ca3d904ddc83"
@@ -7199,11 +7317,41 @@ node-releases@^1.1.53:
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.55.tgz#8af23b7c561d8e2e6e36a46637bab84633b07cee"
integrity sha512-H3R3YR/8TjT5WPin/wOoHOUPHgvj8leuU/Keta/rwelEQN9pA/S2Dx8/se4pZ2LBxSd0nAGzsNzhqwa77v7F1w==
+nodegit-promise@~4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/nodegit-promise/-/nodegit-promise-4.0.0.tgz#5722b184f2df7327161064a791d2e842c9167b34"
+ integrity sha1-VyKxhPLfcycWEGSnkdLoQskWezQ=
+ dependencies:
+ asap "~2.0.3"
+
+nodegit@^0.26.5:
+ version "0.26.5"
+ resolved "https://registry.yarnpkg.com/nodegit/-/nodegit-0.26.5.tgz#1534d8aaa52de7acfbbe18de28df2075de86f7d2"
+ integrity sha512-l9l2zhcJ0V7FYzPdXIsuJcXN8UnLuhQgM+377HJfCYE/eupL/OWtMVvUOq42F9dRsgC3bAYH9j2Xbwr0lpYVZQ==
+ dependencies:
+ fs-extra "^7.0.0"
+ json5 "^2.1.0"
+ lodash "^4.17.14"
+ nan "^2.14.0"
+ node-gyp "^4.0.0"
+ node-pre-gyp "^0.13.0"
+ promisify-node "~0.3.0"
+ ramda "^0.25.0"
+ request-promise-native "^1.0.5"
+ tar-fs "^1.16.3"
+
nodemailer@^6.4.8:
version "6.4.8"
resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.4.8.tgz#aca52886e4e56f71f6b8a65f5ca6b767ca751fc7"
integrity sha512-UbJD0+g5e2H20bWv7Rpj3B+N3TMMJ0MLoLwaGVJ0k3Vo8upq0UltwHJ5BJfrpST1vFa91JQ8cf7cICK5DSIo1Q==
+"nopt@2 || 3":
+ version "3.0.6"
+ resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9"
+ integrity sha1-xkZdvwirzU2zWTF/eaxopkayj/k=
+ dependencies:
+ abbrev "1"
+
nopt@^4.0.1:
version "4.0.3"
resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.3.tgz#a375cad9d02fd921278d954c2254d5aa57e15e48"
@@ -7254,6 +7402,11 @@ normalize-url@^3.0.0:
resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-3.3.0.tgz#b2e1c4dc4f7c6d57743df733a4f5978d18650559"
integrity sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==
+not@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/not/-/not-0.1.0.tgz#c9691c1746c55dcfbe54cbd8bd4ff041bc2b519d"
+ integrity sha1-yWkcF0bFXc++VMvYvU/wQbwrUZ0=
+
npm-bundled@^1.0.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.1.1.tgz#1edd570865a94cdb1bc8220775e29466c9fb234b"
@@ -7289,7 +7442,7 @@ npm-run-path@^4.0.0:
dependencies:
path-key "^3.0.0"
-npmlog@^4.0.2:
+"npmlog@0 || 1 || 2 || 3 || 4", npmlog@^4.0.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b"
integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==
@@ -7299,7 +7452,7 @@ npmlog@^4.0.2:
gauge "~2.7.3"
set-blocking "~2.0.0"
-nth-check@^1.0.2:
+nth-check@^1.0.0, nth-check@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.2.tgz#b2bd295c37e3dd58a3bf0700376663ba4d9cf05c"
integrity sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==
@@ -7485,7 +7638,7 @@ os-tmpdir@^1.0.0, os-tmpdir@~1.0.2:
resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=
-osenv@^0.1.4:
+osenv@0, osenv@^0.1.4:
version "0.1.5"
resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410"
integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==
@@ -8198,6 +8351,13 @@ promise-inflight@^1.0.1:
resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3"
integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM=
+promisify-node@~0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/promisify-node/-/promisify-node-0.3.0.tgz#b4b55acf90faa7d2b8b90ca396899086c03060cf"
+ integrity sha1-tLVaz5D6p9K4uQyjlomQhsAwYM8=
+ dependencies:
+ nodegit-promise "~4.0.0"
+
prompts@^2.0.1:
version "2.3.2"
resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.3.2.tgz#480572d89ecf39566d2bd3fe2c9fccb7c4c0b068"
@@ -8259,6 +8419,14 @@ public-encrypt@^4.0.0:
randombytes "^2.0.1"
safe-buffer "^5.1.2"
+pump@^1.0.0:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/pump/-/pump-1.0.3.tgz#5dfe8311c33bbf6fc18261f9f34702c47c08a954"
+ integrity sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw==
+ dependencies:
+ end-of-stream "^1.1.0"
+ once "^1.3.1"
+
pump@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909"
@@ -8342,6 +8510,11 @@ quick-lru@^4.0.1:
resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f"
integrity sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==
+ramda@^0.25.0:
+ version "0.25.0"
+ resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.25.0.tgz#8fdf68231cffa90bc2f9460390a0cb74a29b29a9"
+ integrity sha512-GXpfrYVPwx3K7RQ6aYT8KPS8XViSXUVJT1ONhoKPE9VAleW42YE+U+8VEyGWt41EnEQW7gwecYJriTI0pKoecQ==
+
randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5:
version "2.1.0"
resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
@@ -8530,7 +8703,7 @@ read-pkg@^5.2.0:
parse-json "^5.0.0"
type-fest "^0.6.0"
-"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6:
+"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.0, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@~2.3.6:
version "2.3.7"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==
@@ -8696,7 +8869,7 @@ request-promise-core@1.1.3:
dependencies:
lodash "^4.17.15"
-request-promise-native@^1.0.8:
+request-promise-native@^1.0.5, request-promise-native@^1.0.8:
version "1.0.8"
resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.8.tgz#a455b960b826e44e2bf8999af64dff2bfe58cb36"
integrity sha512-dapwLGqkHtwL5AEbfenuzjTYg35Jd6KPytsC2/TLkVMz8rm+tNt72MGUWT1RP/aYawMpN6HqbNGBQaRcBtjQMQ==
@@ -8705,7 +8878,7 @@ request-promise-native@^1.0.8:
stealthy-require "^1.1.1"
tough-cookie "^2.3.3"
-request@^2.88.2:
+request@^2.87.0, request@^2.88.2:
version "2.88.2"
resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3"
integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==
@@ -8839,6 +9012,13 @@ rgba-regex@^1.0.0:
resolved "https://registry.yarnpkg.com/rgba-regex/-/rgba-regex-1.0.0.tgz#43374e2e2ca0968b0ef1523460b7d730ff22eeb3"
integrity sha1-QzdOLiyglosO8VI0YLfXMP8i7rM=
+rimraf@2, rimraf@^2.5.2, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.3, rimraf@^2.7.1:
+ version "2.7.1"
+ resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec"
+ integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==
+ dependencies:
+ glob "^7.1.3"
+
rimraf@2.6.3:
version "2.6.3"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab"
@@ -8846,13 +9026,6 @@ rimraf@2.6.3:
dependencies:
glob "^7.1.3"
-rimraf@^2.5.2, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.3, rimraf@^2.7.1:
- version "2.7.1"
- resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec"
- integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==
- dependencies:
- glob "^7.1.3"
-
rimraf@^3.0.0:
version "3.0.2"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
@@ -9007,6 +9180,11 @@ semver@^7.2.1, semver@^7.3.2:
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938"
integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==
+semver@~5.3.0:
+ version "5.3.0"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"
+ integrity sha1-myzl094C0XxgEq0yaqa00M9U+U8=
+
send@0.17.1:
version "0.17.1"
resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8"
@@ -9715,7 +9893,30 @@ tapable@^1.0.0, tapable@^1.1.3:
resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2"
integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==
-tar@^4.4.2:
+tar-fs@^1.16.3:
+ version "1.16.3"
+ resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-1.16.3.tgz#966a628841da2c4010406a82167cbd5e0c72d509"
+ integrity sha512-NvCeXpYx7OsmOh8zIOP/ebG55zZmxLE0etfWRbWok+q2Qo8x/vOR/IJT1taADXPe+jsiu9axDb3X4B+iIgNlKw==
+ dependencies:
+ chownr "^1.0.1"
+ mkdirp "^0.5.1"
+ pump "^1.0.0"
+ tar-stream "^1.1.2"
+
+tar-stream@^1.1.2:
+ version "1.6.2"
+ resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.6.2.tgz#8ea55dab37972253d9a9af90fdcd559ae435c555"
+ integrity sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==
+ dependencies:
+ bl "^1.0.0"
+ buffer-alloc "^1.2.0"
+ end-of-stream "^1.0.0"
+ fs-constants "^1.0.0"
+ readable-stream "^2.3.0"
+ to-buffer "^1.1.1"
+ xtend "^4.0.0"
+
+tar@^4, tar@^4.4.2, tar@^4.4.8:
version "4.4.13"
resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.13.tgz#43b364bc52888d555298637b10d60790254ab525"
integrity sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==
@@ -9845,6 +10046,11 @@ to-arraybuffer@^1.0.0:
resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43"
integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=
+to-buffer@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/to-buffer/-/to-buffer-1.1.1.tgz#493bd48f62d7c43fcded313a03dcadb2e1213a80"
+ integrity sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==
+
to-fast-properties@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
@@ -10046,6 +10252,11 @@ typedarray@^0.0.6:
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
+unfetch@^4.0.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/unfetch/-/unfetch-4.1.0.tgz#6ec2dd0de887e58a4dee83a050ded80ffc4137db"
+ integrity sha512-crP/n3eAPUJxZXM9T80/yv0YhkTEx2K1D3h7D1AJM6fzsWZrxdyRuLN0JH/dkZh1LNH8LxCnBzoPFCPbb2iGpg==
+
unicode-canonical-property-names-ecmascript@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818"
@@ -10103,6 +10314,34 @@ unique-slug@^2.0.0:
dependencies:
imurmurhash "^0.1.4"
+unist-util-is@^4.0.0:
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-4.0.2.tgz#c7d1341188aa9ce5b3cff538958de9895f14a5de"
+ integrity sha512-Ofx8uf6haexJwI1gxWMGg6I/dLnF2yE+KibhD3/diOqY2TinLcqHXCV6OI5gFVn3xQqDH+u0M625pfKwIwgBKQ==
+
+unist-util-parents@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/unist-util-parents/-/unist-util-parents-1.0.3.tgz#9730446164303c40c01bcbe03221d11bc9189a4d"
+ integrity sha512-GA82HBLgPxR+qkOzbti/jxzmkMBDu8iS/mw58iCwLpCl9JpLyGxkVr7nsFpAX956qIsa5yKNKM5SeGS8yCY8Lw==
+ dependencies:
+ es6-weak-map "^2.0.0"
+
+unist-util-select@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/unist-util-select/-/unist-util-select-3.0.1.tgz#787fc452db9ba77f0ade0e7dc53c3d9d4acc79c7"
+ integrity sha512-VQpTuqZVJlRbosQdnLdTPIIqwZeU70YZ5aMBOqtFNGeeCdYn6ORZt/9RiaVlbl06ocuf58SVMoFa7a13CSGPMA==
+ dependencies:
+ css-selector-parser "^1.0.0"
+ not "^0.1.0"
+ nth-check "^1.0.0"
+ unist-util-is "^4.0.0"
+ zwitch "^1.0.0"
+
+universalify@^0.1.0:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
+ integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==
+
unpipe@1.0.0, unpipe@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
@@ -10430,7 +10669,7 @@ which-pm-runs@^1.0.0:
resolved "https://registry.yarnpkg.com/which-pm-runs/-/which-pm-runs-1.0.0.tgz#670b3afbc552e0b55df6b7780ca74615f23ad1cb"
integrity sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs=
-which@^1.2.9:
+which@1, which@^1.2.9:
version "1.3.1"
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
@@ -10584,3 +10823,8 @@ yargs@^15.3.1:
which-module "^2.0.0"
y18n "^4.0.0"
yargs-parser "^18.1.1"
+
+zwitch@^1.0.0:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/zwitch/-/zwitch-1.0.5.tgz#d11d7381ffed16b742f6af7b3f223d5cd9fe9920"
+ integrity sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==