Commit d2cabbeb authored by Quentin's avatar Quentin
Browse files

Change outputs to processOutputs, new endpoint coprus_proces_start, and adding...

Change outputs to processOutputs, new endpoint coprus_proces_start, and adding a new one: corpus_process_continue that each module calls when it finished (so there is no issues if the module takes too much time)
parent a48d8cd0
......@@ -4,10 +4,15 @@
`npm install`
## Set up MongoDB
Make sure to have a mongo instance running, with a database named _chenetal_
## Start server
`npm start`
If you are developping this repository, you can use the following command so that it automatically reloads when you modify a file.
`npm run devstart`
\ No newline at end of file
`npm run devstart`
......@@ -65,6 +65,8 @@ exports.corpus_file_upload = function (req, res) {
fs.mkdirSync(uploadDirectory);
}
let size = 0;
try {
if (files.length) {
files.forEach(file => {
......@@ -74,6 +76,7 @@ exports.corpus_file_upload = function (req, res) {
}
file.mv(filePath);
resData.push({ name: file.name, mimetype: file.mimetype, size: file.size, path: filePath });
size += file.size;
})
}
else {
......@@ -84,8 +87,9 @@ exports.corpus_file_upload = function (req, res) {
// TRY TO WRITE THE BUFFER HERE ?
files.mv(filePath);
resData.push({ name: files.name, mimetype: files.mimetype, size: files.size, path: filePath });
size += files.size;
}
successHandler(res, { uploadedFiles: resData });
successHandler(res, { uploadedFiles: resData, size : size});
}
catch (error) {
errorHandler(res, error);
......@@ -320,4 +324,4 @@ exports.corpus_document_report_get = function (req, res) {
}
}
})
}
\ No newline at end of file
}
......@@ -129,18 +129,24 @@ exports.corpus_process_add_process = async function (req, res) {
errorHandler(res, `No corpus processes were found with id: ${corpusProcessId}`, 404);
}
else {
// Add conlluCol
if (corpusProcess.conlluCols && corpusProcess.conlluCols.length > 0) {
corpusProcess.conlluCols.push(req.body.conlluCol);
}
else {
corpusProcess.conlluCols = [req.body.conlluCol];
}
if (corpusProcess.outputs && corpusProcess.outputs.length > 0) {
corpusProcess.outputs.push(req.body.output);
}
else {
corpusProcess.outputs = [req.body.output];
// Add processOutput if there is one
if (req.body.processOutput) {
if (corpusProcess.processOutputs && corpusProcess.processOutputs.length > 0) {
corpusProcess.processOutputs.push(req.body.processOutput);
}
else {
corpusProcess.processOutputs = [req.body.processOutput];
}
}
corpusProcess = await corpusProcess.save();
successHandler(res, { corpusProcess });
}
......@@ -150,7 +156,7 @@ exports.corpus_process_add_process = async function (req, res) {
}
}
exports.corpus_process_start = async function (req, res) {
exports.corpus_process_start_old = async function (req, res) {
const corpusProcessId = req.params.corpusProcessId;
let corpusProcess;
let started = false;
......@@ -196,3 +202,80 @@ exports.corpus_process_start = async function (req, res) {
}
}
}
exports.corpus_process_start = async function (req, res) {
const corpusProcessId = req.params.corpusProcessId;
let corpusProcess;
let started = false;
let pipeline;
try {
corpusProcess = await CorpusProcessModel.findById(corpusProcessId);
corpusProcess.status = 'Started';
// Easier for debugging (you can just call that endpoint to restart the pipeline)
corpusProcess.currentProcessId = undefined;
await corpusProcess.save();
pipeline = await PipelineModel.findById(corpusProcess.pipelineId);
started = true;
successHandler(res, { message: "Pipeline started" });
// First of all, let's tree tag our corpus
moduleHelper.startTreeTagger(corpusProcessId);
// When it is finished, it will call corpus_process_continue
}
catch (error) {
errorHandler(res, error);
}
}
exports.corpus_process_continue = async function (req, res) {
const corpusProcessId = req.params.corpusProcessId;
try {
let corpusProcess = await CorpusProcessModel.findById(corpusProcessId);
const pipeline = await PipelineModel.findById(corpusProcess.pipelineId);
// If it's not started, start with zero, else, increment
if (corpusProcess.currentProcessId == undefined) {
corpusProcess.currentProcessId = 0;
}
else {
corpusProcess.currentProcessId += 1;
}
// End of the pipeline!
if (pipeline.processes.length <= corpusProcess.currentProcessId) {
corpusProcess.currentProcessingModule = 'Exporter';
await corpusProcess.save();
successHandler(res, 'Let\'s export the conllu file');
console.log(`Starting to export CONLLU for corpus process id: ${corpusProcessId}`);
// Export the pipeline to a conllu file
moduleHelper.startModuleProcess(corpusProcessId, { moduleName: 'Exporter'});
// Should we do another endpoint 'finish'?
corpusProcess.currentProcessingModule = null;
corpusProcess.status = 'Finished';
await corpusProcess.save();
}
else {
let process = pipeline.processes[corpusProcess.currentProcessId]
corpusProcess.currentProcessingModule = process.moduleName;
await corpusProcess.save();
console.log(`Starting module ${process.moduleName} for corpus process id: ${corpusProcessId}`);
moduleHelper.startModuleProcess(corpusProcessId, process);
successHandler(res, `Module ${process.moduleName} has started`);
}
}
catch (error) {
console.error(error);
}
}
......@@ -18,7 +18,8 @@ function nameToRoute(moduleName) {
"Exporter": "http://localhost:3001",
"Modulix": "http://localhost:3002",
"SDMC": "http://localhost:3003",
"Néoveille": "http://localhost:3004"
"Néoveille": "http://localhost:3004",
"Morfetik - Formes Simples": "http://localhost:3005"
}
return routeDict[moduleName];
}
......
{
"name": "Morfetik - Formes Simples",
"description": "Morfetik Description",
"parameters":
[
{
"name": "acceptedCategories",
"label": "Appartenance d'une ou plusieurs catégories",
"description": "Ne traite que les catégories sélectionnées",
"type": "List-Poly",
"items": ["Nom", "Verbe", "Adjectif", "Adverbe", "Conjonction", "Déterminant", "Pronom", "Préposition", "Interjection"],
"default": ["Nom", "Verbe", "Adjectif", "Adverbe", "Conjonction", "Déterminant", "Pronom", "Préposition","Interjection"]
},
{
"name": "selectedColumns",
"label": "Informations souhaitées",
"description": "selectedComumns description",
"type": "List-Poly",
"items": ["Sous-Catégorie", "Temps", "Nombre", "Genre", "Personne", "Notes"],
"default": ["Sous-Catégorie", "Temps", "Nombre", "Genre", "Personne", "Notes"]
}
]
}
\ No newline at end of file
{
"name": "Néoveille",
"description": "Détection de Néologismes",
"description": "Détection de néologismes formels",
"parameters":
[
{
"name": "nodigit",
"label": "Exclusion des chiffres",
"description": "Exclu les candidats qui contiennent des chiffres",
"description": "Exclure les candidats qui contiennent des chiffres",
"type": "Bool",
"items": null,
"default": true
},
{
"name": "lowercaseonly",
"label": "Uniquement des mots en minuscule",
"description": "Exclu les candidats qui ont des caractères en minuscule, cela évite le bruit dû aux noms propres",
"label": "Uniquement les mots en minuscule",
"description": "Exclure les candidats qui ont des caractères en minuscule, cela évite le bruit dû aux noms propres",
"type": "Bool",
"items": null,
"default": true
......@@ -25,20 +25,20 @@
"description": "Expression régulière qui sera utilisée pour filtrer la liste des candidats, si vide, sera équivalent à '.*'",
"type": "String",
"items": null,
"default": "\\w{3,}(?:-\\w{3,}){0,3}"
"default": "^\\w{3,}(?:-\\w{3,}){0,3}$"
},
{
"name": "exclusiondict",
"label": "Dictionnaire d'exclusion",
"description": "Exclu tous les candidats présents de ce dictionnaire",
"description": "Exclure tous les candidats présents de ce dictionnaire",
"type": "Bool",
"items": null,
"default": true
},
{
"name": "spellchecker",
"label": "Heuristique orthographique",
"description": "Exclu les candidats selon une heuristique basée sur Hunspell, permettant notamment d'éviter le bruit dû aux coquilles orthographiques.",
"label": "Correcteur orthographique",
"description": "Exclure les candidats selon une heuristique basée sur Hunspell, permettant notamment d'éviter le bruit dû aux coquilles orthographiques.",
"type": "Bool",
"items": null,
"default": true
......
{
"name": "Prototype",
"description": "Prototype permettant de créer son propre module",
"parameters":
[
{
"name": "parametre1",
"label": "Le nom du paramètre comme il sera inscrit dans le frontend",
"description": "Une description détaillée pour expliquer ce paramètre, qui apparaitra quand on clique sur le point d'interrogation dans le front end",
"type": "Le type de paramètre, parmi : [List-Mono, List-Poly, Int, Bool, String]",
"items": ["La liste des paramètres disponibles, uniquement pour List-Poly et List-Mono, null sinon"],
"default": "La valeur par défaut du paramètre"
}
]
}
\ No newline at end of file
......@@ -10,7 +10,7 @@ const Schema = mongoose.Schema;
* @swagger
* components:
* schemas:
* Output:
* ProcessOutput:
* type: object
* description: data returned by a module at the end of a process
* required:
......@@ -45,7 +45,7 @@ const Schema = mongoose.Schema;
// Output returned by a module
// Can be a text file or something else like a model.
/* Should there be documentId or corpusId? */
const OutputSchema = new Schema({
const ProcessOutputSchema = new Schema({
processId: { type: String, required: false},
moduleName: { type: String, required: true}, // Can be built from processId
content: {
......@@ -212,11 +212,11 @@ const AnnotatedDocumentSchema = new Schema({
* description: list of annotations per document
* items:
* $ref: "#/components/schemas/AnnotatedDocument"
* outputs:
* processOutputs:
* type: array
* description: list of output produced by the pipeline
* items:
* $ref: "#/components/schemas/Output"
* $ref: "#/components/schemas/ProcessOutput"
* currentProcessingModule:
* type: String
* description: Name of the module that is being executed currently by the pipeline. Is null if the pipeline has not started, failed, or finished.
......@@ -244,10 +244,12 @@ const CorpusProcessSchema = new Schema({
// Maybe it's better
/*annotations: { type: [AnnotationSchema]},*/
annotatedDocuments: { type: [AnnotatedDocumentSchema]},
outputs: { type: [OutputSchema]},
//Don't know yet if following are needed, but it seems more relevant to find these
//properties here rather than in Pipeline
currentProcessingModule: { type: String }, // What module is currently processing the corpus?
// The output that a module can return (describing the process that was done)
processOutputs: { type: [ProcessOutputSchema]},
// What module is currently processing the corpus?
currentProcessingModule: { type: String },
// Get the index of the current processing module
currentProcessId: { type: Number},
status: {
type: String,
enum: ['Not started yet', 'Started', 'Processing annotations', 'Finished', 'Failed']
......
{
"name": "chenetal-server",
"version": "1.0.0",
"lockfileVersion": 1,
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "chenetal-server",
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"axios": "^0.21.0",
"cors": "^2.8.5",
"express": "^4.17.1",
"express-fileupload": "^1.2.0",
"jsonwebtoken": "^8.5.1",
"mongoose": "^5.10.5",
"morgan": "^1.10.0",
"passport-jwt": "^4.0.0",
"passport-ldapauth": "^2.1.4",
"swagger-jsdoc": "^4.2.0",
"swagger-ui-express": "^4.1.4",
"yamljs": "^0.3.0"
},
"devDependencies": {
"eslint": "^7.9.0",
"eslint-config-airbnb-base": "^14.2.0",
"eslint-plugin-import": "^2.22.0",
"nodemon": "^2.0.4",
"passport": "^0.4.1"
}
},
"node_modules/@apidevtools/json-schema-ref-parser": {
"version": "9.0.6",
"resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.0.6.tgz",
"integrity": "sha512-M3YgsLjI0lZxvrpeGVk9Ap032W6TPQkH6pRAZz81Ac3WUNF79VQooAFnp8umjvVzUmD93NkogxEwbSce7qMsUg==",
"dependencies": {
"@jsdevtools/ono": "^7.1.3",
"call-me-maybe": "^1.0.1",
"js-yaml": "^3.13.1"
}
},
"node_modules/@apidevtools/openapi-schemas": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/@apidevtools/openapi-schemas/-/openapi-schemas-2.0.4.tgz",
"integrity": "sha512-ob5c4UiaMYkb24pNhvfSABShAwpREvUGCkqjiz/BX9gKZ32y/S22M+ALIHftTAuv9KsFVSpVdIDzi9ZzFh5TCA==",
"engines": {
"node": ">=10"
}
},
"node_modules/@apidevtools/swagger-methods": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/@apidevtools/swagger-methods/-/swagger-methods-3.0.2.tgz",
"integrity": "sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg=="
},
"node_modules/@apidevtools/swagger-parser": {
"version": "10.0.2",
"resolved": "https://registry.npmjs.org/@apidevtools/swagger-parser/-/swagger-parser-10.0.2.tgz",
"integrity": "sha512-JFxcEyp8RlNHgBCE98nwuTkZT6eNFPc1aosWV6wPcQph72TSEEu1k3baJD4/x1qznU+JiDdz8F5pTwabZh+Dhg==",
"dependencies": {
"@apidevtools/json-schema-ref-parser": "^9.0.6",
"@apidevtools/openapi-schemas": "^2.0.4",
"@apidevtools/swagger-methods": "^3.0.2",
"@jsdevtools/ono": "^7.1.3",
"call-me-maybe": "^1.0.1",
"z-schema": "^4.2.3"
}
},
"node_modules/@babel/code-frame": {
"version": "7.10.4",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz",
"integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==",
"dev": true,
"dependencies": {
"@babel/highlight": "^7.10.4"
}
},
"node_modules/@babel/helper-validator-identifier": {
"version": "7.10.4",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz",
"integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==",
"dev": true
},
"node_modules/@babel/highlight": {
"version": "7.10.4",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz",
"integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==",
"dev": true,
"dependencies": {
"@babel/helper-validator-identifier": "^7.10.4",
"chalk": "^2.0.0",
"js-tokens": "^4.0.0"
}
},
"node_modules/@babel/highlight/node_modules/chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"dev": true,
"dependencies": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
"supports-color": "^5.3.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/@eslint/eslintrc": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.1.3.tgz",
"integrity": "sha512-4YVwPkANLeNtRjMekzux1ci8hIaH5eGKktGqR0d3LWsKNn5B2X/1Z6Trxy7jQXl9EBGE6Yj02O+t09FMeRllaA==",
"dev": true,
"dependencies": {
"ajv": "^6.12.4",
"debug": "^4.1.1",
"espree": "^7.3.0",
"globals": "^12.1.0",
"ignore": "^4.0.6",
"import-fresh": "^3.2.1",
"js-yaml": "^3.13.1",
"lodash": "^4.17.19",
"minimatch": "^3.0.4",
"strip-json-comments": "^3.1.1"
},
"engines": {
"node": "^10.12.0 || >=12.0.0"
}
},
"node_modules/@jsdevtools/ono": {
"version": "7.1.3",
"resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz",
"integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg=="
},
"node_modules/@sindresorhus/is": {
"version": "0.14.0",
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz",
"integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==",
"dev": true,
"engines": {
"node": ">=6"
}
},
"node_modules/@szmarczak/http-timer": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz",
"integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==",
"dev": true,
"dependencies": {
"defer-to-connect": "^1.0.1"
},
"engines": {
"node": ">=6"
}
},
"node_modules/@types/body-parser": {
"version": "1.19.0",
"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz",
"integrity": "sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ==",
"dependencies": {
"@types/connect": "*",
"@types/node": "*"
}
},
"node_modules/@types/color-name": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
"integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==",
"dev": true
},
"node_modules/@types/connect": {
"version": "3.4.33",
"resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.33.tgz",
"integrity": "sha512-2+FrkXY4zllzTNfJth7jOqEHC+enpLeGslEhpnTAkg21GkRrWV4SsAtqchtT4YS9/nODBU2/ZfsBY2X4J/dX7A==",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/express": {
"version": "4.17.8",
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.8.tgz",
"integrity": "sha512-wLhcKh3PMlyA2cNAB9sjM1BntnhPMiM0JOBwPBqttjHev2428MLEB4AYVN+d8s2iyCVZac+o41Pflm/ZH5vLXQ==",
"dependencies": {
"@types/body-parser": "*",
"@types/express-serve-static-core": "*",
"@types/qs": "*",
"@types/serve-static": "*"
}
},
"node_modules/@types/express-serve-static-core": {
"version": "4.17.13",
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.13.tgz",
"integrity": "sha512-RgDi5a4nuzam073lRGKTUIaL3eF2+H7LJvJ8eUnCI0wA6SNjXc44DCmWNiTLs/AZ7QlsFWZiw/gTG3nSQGL0fA==",
"dependencies": {
"@types/node": "*",
"@types/qs": "*",
"@types/range-parser": "*"
}
},
"node_modules/@types/json5": {
"version": "0.0.29",
"resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
"integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=",
"dev": true
},
"node_modules/@types/ldapjs": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/@types/ldapjs/-/ldapjs-1.0.9.tgz",
"integrity": "sha512-3PvY7Drp1zoLbcGlothCAkoc5o6Jp9KvUPwHadlHyKp3yPvyeIh7w2zQc9UXMzgDRkoeGXUEODtbEs5XCh9ZyA==",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/mime": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.3.tgz",
"integrity": "sha512-Jus9s4CDbqwocc5pOAnh8ShfrnMcPHuJYzVcSUU7lrh8Ni5HuIqX3oilL86p3dlTrk0LzHRCgA/GQ7uNCw6l2Q=="
},
"node_modules/@types/node": {
"version": "14.11.10",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.11.10.tgz",
"integrity": "sha512-yV1nWZPlMFpoXyoknm4S56y2nlTAuFYaJuQtYRAOU7xA/FJ9RY0Xm7QOkaYMMmr8ESdHIuUb6oQgR/0+2NqlyA=="
},
"node_modules/@types/passport": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@types/passport/-/passport-1.0.4.tgz",
"integrity": "sha512-h5OfAbfBBYSzjeU0GTuuqYEk9McTgWeGQql9g3gUw2/NNCfD7VgExVRYJVVeU13Twn202Mvk9BT0bUrl30sEgA==",
"dependencies": {
"@types/express": "*"
}
},
"node_modules/@types/qs": {
"version": "6.9.5",
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.5.tgz",
"integrity": "sha512-/JHkVHtx/REVG0VVToGRGH2+23hsYLHdyG+GrvoUGlGAd0ErauXDyvHtRI/7H7mzLm+tBCKA7pfcpkQ1lf58iQ=="
},
"node_modules/@types/range-parser": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz",
"integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA=="
},
"node_modules/@types/serve-static": {
"version": "1.13.5",
"resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.5.tgz",
"integrity": "sha512-6M64P58N+OXjU432WoLLBQxbA0LRGBCRm7aAGQJ+SMC1IMl0dgRVi9EFfoDcS2a7Xogygk/eGN94CfwU9UF7UQ==",
"dependencies": {
"@types/express-serve-static-core": "*",
"@types/mime": "*"
}
},
"node_modules/abbrev": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
"dev": true
},
"node_modules/accepts": {
"version": "1.3.7",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
"integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
"dependencies": {
"mime-types": "~2.1.24",
"negotiator": "0.6.2"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/acorn": {
"version": "7.4.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.0.tgz",
"integrity": "sha512-+G7P8jJmCHr+S+cLfQxygbWhXy+8YTVGzAkpEbcLo2mLoL7tij/VG41QSHACSf5QgYRhMZYHuNc6drJaO0Da+w==",
"dev": true,
"bin": {
"acorn": "bin/acorn"
},
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/acorn-jsx": {