Commit ea2c4ce2 authored by El Oualydy Salma's avatar El Oualydy Salma Committed by Pierre-Alain Jachiet
Browse files

Added markdown-include in table documentation pages

to separate the table-schemas from free documentation
parent ae5685b5
......@@ -7,8 +7,8 @@ test-internal-link-and-build:
before_script:
- yarn install
script:
- yarn lint-md
- yarn docs:build
- yarn lint-md
test-external-link:
stage: test
......
const execSync = require('child_process').execSync;
const fs = require('fs');
const schemas_path = "./tables/.schemas";
/**
* For each table documentation file, the markdown table schema is created
* from a json table schema and handlebars template
* this method is called recursively for subdirectories
* @param {*} files an array of filenames
* @param {*} path path to directory
* @param {*} dir the files's directory name
*/
function generateSchemas(path, files, dir) {
files.forEach(filename => {
if (fs.lstatSync(path + '/' + dir + '/' + filename).isDirectory()) {
subFiles = fs.readdirSync(path + '/' + dir + '/' + filename);
generateSchemas(path + '/' + dir, subFiles, filename);
} else {
//generate new schemas in table format using template "template_schemas.hbs" & .json file
execSync('table-schema-to-markdown ' + path + '/' + dir.replace(/\s/g, '\\ ') + '/' + filename +
' --template=.vuepress/template_schema.hbs --fields-format=table >>' + path + '/'
+ dir.replace(/\s/g, '\\ ') + '/' + filename.replace(/\.[^/.]+$/, "") + '.md');
console.log(dir.replace(/\s/g, '\\ ') + '/' + filename.replace(/\.[^/.]+$/, "") + '.md has been generated successfully')
}
});
}
/**
* Searches for all subdirectories and generates a corresponding table schema and associated info
* for each file within
* @param {*} path
*/
function searchAndGenerateSchemas(path) {
//list subdirectories
dirs = fs.readdirSync(path);
//for each directory
dirs.forEach(dir => {
//check if directory
if (fs.lstatSync(path + '/' + dir).isDirectory()) {
//list files
files = fs.readdirSync(path + '/' + dir);
generateSchemas(path, files, dir);
}
});
}
//delete the current generated schemas if exist
execSync("find tables/.schemas -type f -name '*.md' -delete");
//generate new schemas using the distant .json files
searchAndGenerateSchemas(schemas_path);
\ No newline at end of file
const markdownInclude = require('markdown-include');
const fs = require('fs');
const tables_path = "./tables/.sources";
/**
* Overwrites markdown_filename.json and updates the path with right filename and dirname
* The new content is
* '{\n
* "build" : "tables/dirname/filename",\n
* "files" : ["tables/.sources/dirname/filename"]\n
* }'
* @param {*} filename
* @param {*} dirname
*/
function writeJsonFile(filename, dirname) {
//path of the written file
const path = tables_path + "/" + dirname + "/markdown_" + filename + ".json";
//destination folder
var destFolder = "tables";
//source folder
var srcFolder = "tables/.sources";
//content of the file
var content = '{\n "build" : "' + destFolder + '/' + dirname + '/' + filename +
'",\n "files" : ["' + srcFolder + '/' + dirname + '/' + filename + '"]\n }';
//writing file
fs.writeFileSync(path, content);
return path;
}
/**
* For each documentation file, the associated markdown.json file is written
* and compilarion process is carried out
* this method is called recursively for subdirectories
* @param {*} files an array of filenames
* @param {*} path path to directory
* @param {*} dir the files's directory name
*/
function compileDocumentation(files, path, dir) {
//for each file in files
files.forEach(filename => {
// if it is a directory
if (fs.lstatSync(path + '/' + dir + '/' + filename).isDirectory()) {
//list files within
filesList = fs.readdirSync(path + '/' + dir + '/' + filename);
//compile the files found
compileDocumentation(filesList, path + '/' + dir, filename);
} else {
var fullDir = dir;
//fix directory path for PMSI subdirectories
if (dir.includes("PMSI")) fullDir = 'PMSI/' + fullDir;
//write compilation parameters in json file
var jsonPath = writeJsonFile(filename, fullDir);
//execute compilation
markdownInclude.compileFiles(jsonPath).then(function (data) {
//when compilation is done delete json file
fs.unlinkSync(jsonPath);
console.info(markdownInclude.options.build + ' has been built successfully');
});
}
});
}
/**
* Searches for all subdirectories and compiles the files within
* @param {*} path
*/
function searchAndCompile(path) {
//list subdirectories
dirs = fs.readdirSync(path);
//for each directory
dirs.forEach(dir => {
//check if directory
if (fs.lstatSync(path + '/' + dir).isDirectory()) {
//list files
files = fs.readdirSync(path + '/' + dir);
//compile
compileDocumentation(files, path, dir);
}
});
}
searchAndCompile(tables_path);
\ No newline at end of file
......@@ -5,15 +5,19 @@ const fs = require('fs');
* @param {*} directory
* @param {*} filename
*/
function getMarkdownTitle(directory, filename){
function getMarkdownTitle(directory, filename) {
var text = fs.readFileSync(directory + '/' + filename);
//returns the first line of the text
var header= text.toString().split('\n').shift()
/*
applies the following transformation
'# Les actes et consultations externes' -> 'les actes et consultations externes'
*/
.slice(1).toLowerCase().trim();
var lines = text.toString().split('\n');
var header = text.toString().split('\n')[0];
for (line of lines) {
if (line.startsWith('# ')) {
/* applies the following transformation :
* '# Les actes et consultations externes' -> 'les actes et consultations externes'
*/
header = line.slice(1).toLowerCase().trim();
break;
}
}
return header
}
......@@ -23,25 +27,25 @@ function getMarkdownTitle(directory, filename){
*/
function listMarkdownFilesInDirectory(directoryName) {
return fs
// returns an array of all the filenames in a directory
.readdirSync('./' + directoryName)
// returns all filenames except README.md
.filter(function (filename) {
return filename !== 'README.md';
})
//returns only filenames that have an .md extension
.filter(function (filename) {
return filename.slice(-3) === '.md';
})
// returns a case insensitive sorting between file titles
.sort(function (a, b) {
return getMarkdownTitle(directoryName, a)
.localeCompare(getMarkdownTitle(directoryName, b));
})
//returns a new array with a transformation on filenames (adding the directory name)
.map(function (filename) {
return '/' + directoryName + '/' + filename.slice(0, -3);
});
// returns an array of all the filenames in a directory
.readdirSync('./' + directoryName)
// returns all filenames except README.md
.filter(function (filename) {
return filename !== 'README.md';
})
//returns only filenames that have an .md extension
.filter(function (filename) {
return filename.slice(-3) === '.md';
})
// returns a case insensitive sorting between file titles
.sort(function (a, b) {
return getMarkdownTitle(directoryName, a)
.localeCompare(getMarkdownTitle(directoryName, b));
})
//returns a new array with a transformation on filenames (adding the directory name)
.map(function (filename) {
return '/' + directoryName + '/' + filename.slice(0, -3);
});
}
/**
......@@ -50,12 +54,16 @@ function listMarkdownFilesInDirectory(directoryName) {
*/
function listSubDirectories(directoryName) {
return fs
// returns an array of all the filenames in a directory
.readdirSync('./' + directoryName)
//returns only the directories
.filter(function (filename) {
return fs.lstatSync('./' + directoryName + '/' + filename).isDirectory();
})
// returns an array of all the filenames in a directory
.readdirSync('./' + directoryName)
//returns only the directories
.filter(function (filename) {
return fs.lstatSync('./' + directoryName + '/' + filename).isDirectory();
})
//ignore .schemas and .sources directories in /tables
.filter(function (filename) {
return filename !== ".schemas" && filename !== ".sources";
})
}
/**
......@@ -65,9 +73,9 @@ function listSubDirectories(directoryName) {
const getSidebarGroup = function (directoryPath) {
const lastDirectory = directoryPath.split("/").pop();
const sidebarGroup = {};
sidebarGroup["title"] = lastDirectory.charAt(0).toUpperCase() + lastDirectory.slice(1);
// checks if it contains a README file
if (fs.existsSync('./' + directoryPath + '/README.md')) {
sidebarGroup["path"] = '/' + directoryPath + '/';
......
{{#if title}}
- Description : {{{title}}}
{{/if}}
{{#if primaryKey}}
<br />
- Clé primaire : {{#each primaryKey}}`{{this}}`{{#unless @last}}, {{/unless}}{{else}}`{{this.primaryKey}}`{{/each}}
{{/if}}
{{#if foreignKeys}}
<br />
- Clé(s) étrangère(s) : <br />
{{#each foreignKeys}}
{{#each this.fields}}`{{this}}`{{#unless @last}}, {{/unless}}{{else}}`{{this.fields}}`{{/each}} => table [{{this.reference.resource}}](/tables/{{this.reference.resource}}) [ {{#each this.reference.fields}}`{{this}}`{{#unless @last}}, {{/unless}}{{else}}`{{this.reference.fields}}`{{/each}} ]<br />
{{/each}}
{{/if}}
## Schéma de la table {{{name}}}
<br />
<div>
<a href="https://gitlab.com/healthdatahub/schema-snds/edit/master/schemas/{{#startsWith "PMSI" produit}}{{replace produit "PMSI " "PMSI/PMSI%20"}}{{else}}{{encodeURI produit}}{{/startsWith}}/{{name}}.json"
arget="_blank" rel="noopener noreferrer">> Éditer le schéma</a>
<OutboundLink />
</div>
<br />
Nom|Type|Description|Propriétés
-|-|-|-
{{#each fields}}
`{{name}}`|
{{~intlGet (append "type." type)}}|
{{~description}}|
{{~#if constraints.unique}}<p>{{intlGet "fieldProperties.constraints.unique"}}</p>{{/if}}
{{~#if constraints.description}}<p>{{constraints.description}}</p>{{/if}}|
{{/each}}
......@@ -141,7 +141,7 @@ export default {
+ `/edit`
+ `/${docsBranch}/`
+ (docsDir ? docsDir.replace(endingSlashRE, '') + '/' : '')
+ path
+ path.replace('tables','tables/.sources')
)
},
......
This diff is collapsed.
......@@ -4,6 +4,9 @@
"repository": "https://gitlab.com/healthdatahub/documentation-snds.git",
"license": "MPL-2.0",
"dependencies": {
"@opendataschema/table-schema-to-markdown": "^0.4.1",
"handlebars-helpers": "^0.10.0",
"markdown-include": "^0.4.3",
"markdown-it-footnote": "^3.0.2",
"moment": "^2.24.0",
"remark": "^10.0.1",
......@@ -11,12 +14,17 @@
"remark-lint": "^6.0.4",
"remark-lint-no-dead-urls": "^0.4.1",
"remark-validate-links": "^9.0.1",
"vue": "^2.6.11",
"vue-loader": "^15.8.3",
"vue-server-renderer": "^2.6.11",
"vue-template-compiler": "^2.6.11",
"vuepress": ">= v1.2.0"
},
"devDependencies": {},
"scripts": {
"docs:dev": "cp -r files .vuepress/public/files && vuepress dev",
"docs:build": "cp -r files .vuepress/public/files && vuepress build",
"start": "cp -r files .vuepress/public/files && node .vuepress/generate-schemas.js && node .vuepress/include-tables.js",
"docs:dev": "yarn run start && vuepress dev",
"docs:build": "yarn run start && vuepress build",
"lint-md": "remark --frail --use remark-validate-links . --quiet",
"extended-lint-md": "remark --frail --use remark-validate-links --use remark-lint-no-dead-urls . --quiet"
}
......
*
!.schemas/
!.schemas/**
!.schemas/**/*.json
.schemas/**/*.md
!.sources/
!.sources/**/*
!BENEFICIAIRE/
!CARTOGRAPHIE_PATHOLOGIES/
!Causes de décès/
!DAMIR/
!DCIR/
!DCIR_DCIRS/
!DCIRS/
!EGB/
!PMSI/
PMSI/**/*
!PMSI/PMSI HAD/
!PMSI/PMSI MCO/
!PMSI/PMSI RIM-P/
!PMSI/PMSI SSR/
!.gitignore
!.keep
\ No newline at end of file
{
"fields": [
{
"name": "BEN_NIR_PSA",
"description": "Identifiant anonyme du patient dans le SNIIRAM",
"type": "string",
"nomenclature": "-",
"length": "17",
"format": "default",
"constraints": {
"unique": true,
"description": "Unicité fausse sans le rang gémellaire. Contrainte nécessaire pour les clés étrangère du PMSI, qui n'a pas le rang gémellaire"
},
"dateCreated": "",
"dateDeleted": "",
"dateMissing": [],
"observation": "",
"regle_gestion": "",
"type_oracle": "string"
},
{
"name": "BEN_RNG_GEM",
"description": "rang de naissance du bénéficiaire",
"type": "number",
"nomenclature": "IR_BER_V",
"length": "2",
"format": "default",
"dateCreated": "",
"dateDeleted": "",
"dateMissing": [],
"observation": "",
"regle_gestion": "La règle de calcul du rang du bénéficiaire dans le SNIIRAM est la suivante :\n- le rang de l’ouvreur de droits est toujours égal à 1,\n- si un ayant droit a la même date de naissance que l’ouvreur de droits, son rang est égal à 2,\n- un enfant né d’une naissance unique a un rang égal à 1,\n- lorsqu’il y a des naissances multiples, chaque enfant est différencié par son rang (1 pour le 1er, 2 pour le second, …).",
"type_oracle": "number"
},
{
"name": "BEN_NIR_ANO",
"description": "NIR pseudonymisé du bénéficiaire",
"type": "string",
"nomenclature": "-",
"length": "17",
"format": "default",
"dateCreated": "",
"dateDeleted": "",
"dateMissing": [],
"observation": "",
"regle_gestion": "",
"type_oracle": "string"
},
{
"name": "BEN_IDT_ANO",
"description": "Identifiant bénéficiaire anonymisé",
"type": "string",
"nomenclature": "-",
"length": "18",
"format": "default",
"constraints": {
"unique": true
},
"dateCreated": "",
"dateDeleted": "",
"dateMissing": [],
"observation": "",
"regle_gestion": "",
"type_oracle": "string"
},
{
"name": "BEN_IDT_TOP",
"description": "Top identifiant bénéficiaire Anonymisé",
"type": "number",
"nomenclature": "-",
"length": "1",
"format": "default",
"dateCreated": "",
"dateDeleted": "",
"dateMissing": [],
"observation": "",
"regle_gestion": "",
"type_oracle": "number"
},
{
"name": "ASS_NIR_ANO",
"description": "Matricule anonymisé de l'ouvreur de droits",
"type": "string",
"nomenclature": "-",
"length": "17",
"format": "default",
"dateCreated": "",
"dateDeleted": "",
"dateMissing": [],
"observation": "",
"regle_gestion": "",
"type_oracle": "string"
},
{
"name": "BEN_IDT_MAJ",
"description": "Date d'alimentation du NIR BEN_NIR_NAO",
"type": "date",
"nomenclature": "-",
"length": null,
"format": "default",
"dateCreated": "",
"dateDeleted": "",
"dateMissing": [],
"observation": "",
"regle_gestion": "",
"type_oracle": "date"
},
{
"name": "BEN_CDI_NIR",
"description": "Code d'identification du NIR",
"type": "string",
"nomenclature": "IR_NIR_V",
"length": "2",
"format": "default",
"dateCreated": "",
"dateDeleted": "",
"dateMissing": [],
"observation": "",
"regle_gestion": "",
"type_oracle": "string"
},
{
"name": "BEN_NAI_ANN",
"description": "Année de naissance du bénéficiaire",
"type": "string",
"nomenclature": "-",
"length": "4",
"format": "default",
"dateCreated": "",
"dateDeleted": "",
"dateMissing": [],
"observation": "",
"regle_gestion": "",
"type_oracle": "string"
},
{
"name": "BEN_NAI_MOI",
"description": "Mois de naissance du bénéficiaire",
"type": "string",
"nomenclature": "-",
"length": "2",
"format": "default",
"dateCreated": "",
"dateDeleted": "",
"dateMissing": [],
"observation": "",
"regle_gestion": "",
"type_oracle": "string"
},
{
"name": "BEN_SEX_COD",
"description": "Code sexe du bénéficiaire",
"type": "number",
"nomenclature": "IR_SEX_V",
"length": "1",
"format": "default",
"dateCreated": "",
"dateDeleted": "",
"dateMissing": [],
"observation": "",
"regle_gestion": "",
"type_oracle": "number"
},
{
"name": "BEN_DCD_DTE",
"description": "Date de décès du bénéficiaire",
"type": "date",
"nomenclature": "IR_DTE_V",
"length": "8",
"format": "default",
"dateCreated": "",
"dateDeleted": "",
"dateMissing": [],
"observation": "",
"regle_gestion": "",
"type_oracle": "date"
},
{
"name": "BEN_DCD_AME",
"description": "Année et mois de décès du bénéficiaire",
"type": "string",
"nomenclature": "-",
"length": "6",
"format": "default",
"dateCreated": "",
"dateDeleted": "",
"dateMissing": [],
"observation": "",
"regle_gestion": "",
"type_oracle": "string"
},
{
"name": "ORG_AFF_BEN",
"description": "Code de l'organisme d'affiliation",
"type": "string",
"nomenclature": "IR_ORG_V",
"length": "9",
"format": "default",
"dateCreated": "",
"dateDeleted": "",
"dateMissing": [],
"observation": "",
"regle_gestion": "",
"type_oracle": "string"
},
{
"name": "BEN_RES_DPT",
"description": "Département de résidence du bénéficiaire",
"type": "string",
"nomenclature": "IR_DPT_V",
"length": "3",
"format": "default",
"dateCreated": "",
"dateDeleted": "",
"dateMissing": [],
"observation": "",
"regle_gestion": "",
"type_oracle": "string"
},
{
"name": "BEN_RES_COM",
"description": "commune de résidence du destinataire du règlement",
"type": "string",
"nomenclature": "IR_GEO_V",
"length": "3",
"format": "default",
"dateCreated": "",
"dateDeleted": "",
"dateMissing": [],
"observation": "",