find dates works

This commit is contained in:
Tykayn 2023-03-05 23:13:16 +01:00 committed by tykayn
parent 8bef6d4d6a
commit bd538bcee8
5 changed files with 219 additions and 59 deletions

View File

@ -6,5 +6,8 @@
}, },
"scripts": { "scripts": {
"start": "node app.js" "start": "node app.js"
},
"devDependencies": {
"moment": "^2.29.4"
} }
} }

View File

@ -2,20 +2,30 @@
* convertir un fichier .org vers des données structurées en json * convertir un fichier .org vers des données structurées en json
* @type {*} * @type {*}
*/ */
// const fileToParse = process.argv[0]
import fs from 'node-fs'; import fs from 'node-fs';
const sourceFileName = 'demo.org' import moment from 'moment';
const sourceFilePath = './sources/'+sourceFileName;
/**********************
* initialize configs
**********************/
const sourceFileName = 'demo_more.org'
const sourceFilePath = './sources/' + sourceFileName;
let headers = []
let tasksObjectsForJsonExport = []
let headersByKind = {}
let writeJsonAfterParse = false;
/**************************************************************
* fetch the source orgmode file to read its contents
*************************************************************/
console.log('parse some org file', sourceFilePath) console.log('parse some org file', sourceFilePath)
if (!sourceFilePath) { if (!sourceFilePath) {
console.error('pas de fichier à ouvrir') console.error('pas de fichier à ouvrir')
} }
let headers = []
let tasksObjectsForJsonExport = []
let headersByKind = {}
fs.stat(sourceFilePath, function (err, stat) { fs.stat(sourceFilePath, function (err, stat) {
if (err == null) { if (err == null) {
console.log(`File ${sourceFilePath} exists`); console.log(`File ${sourceFilePath} exists`);
@ -28,26 +38,41 @@ fs.stat(sourceFilePath, function (err, stat) {
} }
}); });
/**********************
* search elements
*********************/
let stateKeywordList = ['SOMEDAY', 'NEXT', 'TODO', 'CANCELLED', 'DONE', 'WAITING'];
let dateKeywordList = ['CREATED', 'SCHEDULED', 'DEADLINE', 'CLOSED','Refiled'];
let sectionKeywordList = ['PROPERTIES', 'LOGBOOK', 'END'];
let propertiesSection = {}
let logBookSection = {}
let keyword = 'SOMEDAY'; let headerKeywordSearch = '[' + stateKeywordList.join('|') + ']'
let keywordList = ['SOMEDAY', 'NEXT','TODO', 'CANCELLED','DONE', 'WAITING']; /**
* task object example
* @type {{level: string, header: string, dates: {CREATED: string, DONE: string, REFILED: string}, state: string, content: string, properties: {}, tags: [], tagsInherited: []}}
*/
let task = { let task = {
header : "", header: "",
level : "", level: "",
content : "", content: "",
state : "", state: "",
tags : [], tags: [],
tagsInherited : [], tagsInherited: [],
dates : { dates: {},
'CREATED':'', logbook: {},
'REFILED':'', properties: {},
'DONE':'',
},
properties : {},
} }
let currentTask = Object.create(task); // init first task object as empty clone
let currentTask = {...task};
let isHeader = false;
let isProperty = false;
let isLogbook = false;
let isFirst = true;
/**********************
* loop to parse all
*********************/
fs.readFile(sourceFilePath, 'utf8', function (err, data) { fs.readFile(sourceFilePath, 'utf8', function (err, data) {
if (err) { if (err) {
return console.log(err); return console.log(err);
@ -61,54 +86,125 @@ fs.readFile(sourceFilePath, 'utf8', function (err, data) {
everyline.forEach((line) => { everyline.forEach((line) => {
// gérer la création d'objets définissant les tâches et leurs propriétés
if (line.match(/^\*+? /)) { if (line.match(/^\*+? /)) {
// add last task to export list // add last task to export list
if (!isFirst) {
tasksObjectsForJsonExport.push(currentTask) tasksObjectsForJsonExport.push(currentTask)
console.log('currentTask.dates', currentTask.dates)
currentTask = {...task};
} else {
isFirst = false;
}
isHeader = true;
// compter les étoiles pour trouver le niveau du header
currentTask.level = line.match(/\*/g)?.length
// create a new task // create a new task
currentTask = Object.create(task);
line = line.replace('*', '')
line = line.replace(stateKeywordList, [].fill('', 0, stateKeywordList.length))
headers.push(line) headers.push(line)
currentTask.header = line; currentTask.header = line;
keywordList.forEach(keyword => { stateKeywordList.forEach(keyword => {
lookForKeywordInLine(line, keyword) let keywordIsFound = lineHasKeyword(line, keyword)
if(line.indexOf('* '+keyword) !== -1){ if (keywordIsFound) {
currentTask.state = keyword currentTask.state = keyword
} }
// compter les étoiles pour trouver le niveau du header })
currentTask.level = line.match(/\*/g).length
// trouver les tags
let tagsFound = line.match(/\:(.*)\:/g) let tagsFound = line.match(/\:(.*)\:/g)
console.log('tagsFound', tagsFound) if (tagsFound) {
if(tagsFound){
tagsFound = tagsFound[0]; tagsFound = tagsFound[0];
console.log('tagsFound', tagsFound) console.log('tagsFound', tagsFound)
tagsFound = tagsFound.split(':').filter(item => item.length ) tagsFound = tagsFound.split(':').filter(item => item.length)
currentTask.tags = tagsFound; currentTask.tags = tagsFound;
} }
})
// TODO gérer la création d'objets définissant les tâches et leurs propriétés
// fin des recherches dans la ligne de Header
} else {
isHeader = false;
}
// examen des lignes de corps de tâche, ou de corps de section suite au header.
// classer les dates de création, cloture, et de logbook
let dateFound = searchDate(line)
if(dateFound){
dateKeywordList.forEach(keyword => {
if (lineHasSubstring(line, keyword)) {
if (!currentTask.dates[keyword]) {
currentTask.dates[keyword] = '';
}
currentTask.dates[keyword] = new Date(dateFound[0]);
} else {
// console.log('keyword', keyword)
} }
}) })
}
// ajouter le corps complet de la section après le header
if (line.length && !isHeader) {
let cleanedLine = line.replace(/\s\s/g, ' ')
cleanedLine = line.replace(/ {2,}/g, ' ')
console.log('line', cleanedLine)
currentTask.corpus += `
` + cleanedLine;
}
})
// ajouter la dernière tâche parsée
tasksObjectsForJsonExport.push(currentTask)
console.log('headers', headers) console.log('headers', headers)
console.log(" parsing fini") console.log(" parsing fini")
console.log('nombre de lignes', everyline.length) stateKeywordList.forEach(keyword => console.log('nombre de headers', keyword, headersByKind[keyword]?.length))
console.log('nombre de headers', headers.length)
keywordList.forEach(keyword => console.log('nombre de headers',keyword, headersByKind[keyword]?.length))
console.log('tasksObjectsForJsonExport', tasksObjectsForJsonExport)
// writeJsonFile('export_'+sourceFileName +'.json' , JSON.stringify(tasksObjectsForJsonExport)); const jsonContent = {
statistics: {
lines_count: everyline.length,
headers_count: headers.length,
},
meta_data: {
author: '@tykayn@mastodon.Cipherbliss.com',
generated_at: new Date(),
generated_from_file: sourceFilePath + sourceFileName,
sources: 'https://forge.chapril.org/tykayn/org-report-stats.git'
},
tasks_list: tasksObjectsForJsonExport
}
// console.log('tasksObjectsForJsonExport', jsonContent)
if (writeJsonAfterParse) {
writeJsonFile('export_' + sourceFileName + '.json', JSON.stringify(jsonContent));
}
return; return;
}) })
function lookForKeywordInLine(line, keyword='TODO') { function lineHasKeyword(line, keyword = 'TODO') {
let isFound = (line.indexOf('* ' + keyword) !== -1)
if ( line.indexOf('* '+keyword) !== -1) { if (isFound) {
createNewHeaderKind(keyword) createNewHeaderKind(keyword)
headersByKind[keyword].push(line); headersByKind[keyword].push(line);
} }
return isFound;
}
function lineHasSubstring(line, keyword) {
return (line.indexOf(keyword) !== -1)
} }
function createNewHeaderKind(keyword) { function createNewHeaderKind(keyword) {
@ -117,9 +213,45 @@ function createNewHeaderKind(keyword) {
} }
} }
/**
* chercher des dates et heures au format
* YYYY-MM-DD HH:II:SS
*
* @param line
* @returns {*}
*/
function searchDate(line) {
// return line.match(/[(\d{4}\-\d{2}\-\d{2} ?\d{2}?\:?\d{2}?\:?\d{2}?)(\d{4}\-\d{2}\-\d{2})]/)
let simpleDay = line.match(/\d{4}\-\d{2}\-\d{2} \w{3}?\.?/)
let simpleDayHour = line.match(/\d{4}\-\d{2}\-\d{2} \w{3}?\.? \d{2}\:\d{2}/)
let simpleDayHourSec = line.match(/\d{4}\-\d{2}\-\d{2} \w{3}?\.? \d{2}\:\d{2}\:\d{2}/)
if(simpleDayHourSec){
return simpleDayHourSec;
}
if(simpleDayHour){
return simpleDayHour;
}
if(simpleDay){
return simpleDay;
}
}
/**
* afin de trouver la première date liée à une tâche parmi celles mentionnées, il faut comparer les dates
* @param date1
* @param date2
*/
function compareDatesAndKeepOldest(date1, date2) {
date1 = moment(date1)
date2 = moment(date2)
}
function writeJsonFile(fileName, fileContent) { function writeJsonFile(fileName, fileContent) {
console.log('write file ', fileName); console.log('write file ', fileName);
return fs.writeFile( return fs.writeFile(
`./output/${fileName}`, `./output/${fileName}`,
fileContent, fileContent,

View File

@ -1,10 +1,4 @@
* coucou la démo de fichier org
* voilà un 2e header
* TODO faire une démo * TODO faire une démo
* NEXT écrire le fichier de démo [1/3] :demo: DEADLINE: <2023-02-28 mar. 12:30>
** SOMEDAY oh un sous header, niveau 2 :subtil: ** NEXT écrire le fichier de démo [1/3] :demo:
** CANCELLED un truc pas fait au final CREATED: <2023-02-28 mar.>
** DONE et voilà ça c'est fait :projet_fini:ARCHIVE:
CLOSED : [2023-03-04 15:00]
* pas mal hein
c'est un texte de description

23
sources/demo_more.org Normal file
View File

@ -0,0 +1,23 @@
* coucou la démo de fichier org
* voilà un 2e header
* TODO faire une démo
DEADLINE: <2023-02-28 mar.>
* NEXT écrire le fichier de démo [1/3] :demo:
CREATED: <2023-02-28 mar.>
SCHEDULED: <2023-02-28 mar.>
DEADLINE: <2023-02-28 mar.>
** SOMEDAY oh un sous header, niveau 2 avec logbook et propriétés :subtil:
CREATED: <2023-02-28 mar.>
:PROPERTIES:
:CREATED: [2023-02-28 11:36:23]
:END:
:LOGBOOK:
- State "TODO" from "SOMEDAY" [2023-02-28 mar. 12:12]
- Refiled on [2023-02-28 mar. 11:50]
:END:
** CANCELLED un truc pas fait au final
** DONE et voilà ça c'est fait :projet_fini:ARCHIVE:
CLOSED : [2023-03-04 15:00]
* pas mal hein
c'est un texte de description

View File

@ -1052,6 +1052,13 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"moment@npm:^2.29.4":
version: 2.29.4
resolution: "moment@npm:2.29.4"
checksum: 0ec3f9c2bcba38dc2451b1daed5daded747f17610b92427bebe1d08d48d8b7bdd8d9197500b072d14e326dd0ccf3e326b9e3d07c5895d3d49e39b6803b76e80e
languageName: node
linkType: hard
"ms@npm:2.1.2": "ms@npm:2.1.2":
version: 2.1.2 version: 2.1.2
resolution: "ms@npm:2.1.2" resolution: "ms@npm:2.1.2"
@ -1268,6 +1275,7 @@ __metadata:
resolution: "root-workspace-0b6124@workspace:." resolution: "root-workspace-0b6124@workspace:."
dependencies: dependencies:
d3: ^7.8.2 d3: ^7.8.2
moment: ^2.29.4
node-fs: ^0.1.7 node-fs: ^0.1.7
nodemon: ^2.0.19 nodemon: ^2.0.19
languageName: unknown languageName: unknown