How to sort on the result of a bunch of formulas - useful for papers

I have a collection of papers that I have summarized by the number of lines (NL) of the critique, highlights; the number of property-pairs for terminology, field cases, physical mechanisms, citations; number of figures attached to the source note of the paper; number of extractions entered as callouts; number of references per paper in their own reference note; number of essential plots; and number of reverse engineering calculations performed on some papers. This all make a summary table like this:

Sort of I could make a ranking by the amount of exploration and extractions on a literature source. A paper rating wouldn’t be as subjective anymore.

This is the script for the output:

function countPropertyValue1LD(page, propText) {
	return page.file.inlinks.values
		.filter(f => dv.func.contains(dv.page(f.path).related,
			 dv.func.link(propText))).length
}

function referenceLink(page, str) {
	let values = page.file.inlinks.values
	let filtered = values
		.filter(p => p.path.contains(str))
	return filtered
}

function numOfRefs(page, str) {
	let filtered = referenceLink(page, str)
	return filtered[0]?.path ?
	 dv.page(filtered[0]?.path).file.lists.length : 0
}

function numOf(property) {
	return !property ? 0 : typeof(property) == "string" 
					  ? 1 : property.length
}

function numFigures(page) {
	const embeds = page.file.outlinks
		.where(p => p.embed)
		.where(p => p.path.substr(p.path.length-3) == "png" )
	return (embeds.length)
}

function numListElem(page, section) {
	let values = page.file.lists.section.subpath.values
	return values ? 
	values.filter((w) => w === section).length : 0
}

async function numCallouts(page) {
   const regex = />\s\[\!(\w+)\]\s(.+?)((\n>\s.*?)*)\n/ 
   const file = app.vault.getAbstractFileByPath(page.file.path)
   const contents =  await app.vault.read(file)
   let count = 0
   for (const co of contents.match(new RegExp(regex, 'sg'))) {
	 count = count + 1
   }
   return count
}

let pages = dv.pages('"Sources"')

dv.table(
	["Paper", "Crit", "HL", "Terms", "Cases", "Mech", "Cits", "Figs", 
	"Extracts", "Refs", "EPlots", "RevEng", "Sum"],
	await Promise.all(
	pages
		.where(page => page.type == "paper")
		// .sort(page => page.file.name, 'asc')
		// .sort(page => page.z_rating, 'desc')
		.map(async page => [
			dv.fileLink(page.file.name, false, dv.func.substring(page.file.name, 1, 13)),	
			numListElem(page, "Critique"),                      // section, list
			numListElem(page, "Highlights"),                    // section, list
			numOf(page.term),                                   // properties
			numOf(page.case),                                   // properties
			numOf(page.mechanism),                              // properties
			numOf(page.paper),                                  // properties
			numFigures(page),                                   // outlinks, embed
			await numCallouts(page),                            // regex
			numOfRefs(page, "References"),                      // inlinks, 1LD, filename, list
			countPropertyValue1LD(page, "essential plots"),     // inlinks, 1LD, property
			countPropertyValue1LD(page, "reverse engineering"), // inlinks, 1LD, property
			numListElem(page, "Critique") + numListElem(page, "Highlights") 
			+ numOf(page.term) + numOf(page.case) + numOf(page.mechanism) + numOf(page.paper)
			+ numFigures(page) + await numCallouts(page) 
			+ Math.round(Math.log(numOfRefs(page)+0.1)+0.5, 0)
			+ countPropertyValue1LD(page, "essential plots") * 10
			+ countPropertyValue1LD(page, "reverse engineering") * 20
			]
		 )
	  )
 )

My question is: how would I be able to sort the papers by the column Sum, if Sum is the weighted total of the rest of the columns which is made of a bunch of formulas?

For the sake of simplification let’s say we have only three columns: Critique, Highlights and Sum.

Query:

```dataviewjs
let pages = dv.pages('"Sources"');

let data = await Promise.all(
	pages
		.where(page => page.type == "paper")
		.map(async page => [
			dv.fileLink(page.file.name),	
			numListElem(page, "Critique"),
			numListElem(page, "Highlights"),
			numListElem(page, "Critique") + numListElem(page, "Highlights")
		])
);

// Sort by ascendant order using the last column
data = data.sort((a, b) => a[data[0].length - 1] - b[data[0].length - 1]); 

// Sort by descendant order
//data = data.sort((a, b) => b[data[0].length - 1] - a[data[0].length - 1]); 

dv.table(
	["Paper","Crit","HL","Sum"],
	data
);
```

Output for ascendant order:

Output for descendant order:

1 Like

You can’t sort on a column definition, so the two most common alternatives is either to sort the table afterwards, where you need to define a sort function like in the other post, or you could define the column earlier on in your query and use the default sort mechanics.

The following is untested, but it should work :slight_smile:

// keep your stuff in this section

dv.table(
	["Paper", "Crit", "HL", "Terms", "Cases", "Mech", "Cits", "Figs", 
	"Extracts", "Refs", "EPlots", "RevEng", "Sum"],
	await Promise.all(
	pages
		.where(page => page.type == "paper")
        .mutate(page => page.sum =

            numListElem(page, "Critique") + numListElem(page, "Highlights") 
			+ numOf(page.term) + numOf(page.case) + numOf(page.mechanism) + numOf(page.paper)
			+ numFigures(page) + await numCallouts(page) 
			+ Math.round(Math.log(numOfRefs(page)+0.1)+0.5, 0)
			+ countPropertyValue1LD(page, "essential plots") * 10
			+ countPropertyValue1LD(page, "reverse engineering") * 20 )
       
		.sort(page => page.sum, 'asc')
		// .sort(page => page.z_rating, 'desc')
		.map(async page => [
			dv.fileLink(page.file.name, false, dv.func.substring(page.file.name, 1, 13)),	
			numListElem(page, "Critique"),                      // section, list
			numListElem(page, "Highlights"),                    // section, list
			numOf(page.term),                                   // properties
			numOf(page.case),                                   // properties
			numOf(page.mechanism),                              // properties
			numOf(page.paper),                                  // properties
			numFigures(page),                                   // outlinks, embed
			await numCallouts(page),                            // regex
			numOfRefs(page, "References"),                      // inlinks, 1LD, filename, list
			countPropertyValue1LD(page, "essential plots"),     // inlinks, 1LD, property
			countPropertyValue1LD(page, "reverse engineering"), // inlinks, 1LD, property
			page.sum
			]
		 )
	  )
 )

The gist of it is to use .mutate() to introduce a new variable into the row, and then use that to sort on.

2 Likes

Elegant @holroy ! I tested and it works :wink:

let pages = dv.pages('"Sources"');

let data = await Promise.all(
	pages
		.where(page => page.type == "paper")
		.mutate(page => 
			page.sum = numListElem(page, "Critique") + numListElem(page, "Highlights")
		)
		.sort(page => page.sum, 'asc')
		.map(async page => [
			dv.fileLink(page.file.name),	
			numListElem(page, "Critique"),
			numListElem(page, "Highlights"),
			page.sum
		])
);

dv.table(
	["Paper","Crit","HL","Sum"],
	data
);
 

In retrospect I see you do an await to calculate the sum. That might complicate stuff somewhat, as you probably need to make the mutate() can async too and possibly do some more promise stuff…

Alternatively you could switch it around and set this value in the mutate() callback as well, and save yourself one call to this function, and make just the mutate() function async. But it’s too late in the evening to write that out for me, so I hope you understand what I’m rambling about and are able to execute the idea of it.

1 Like

Thanks @holroy. Good stuff!
Unfortunately, the sorting only works if I remove //+ await numCallouts(page) from the mutate function. By the way, I needed to add the async to .mutate(async page => page.sum = first, otherwise I get the weird error “Evaluation Error: SyntaxError: missing ) after argument list”.

If I keep that line and remove the await only, I get this message: “[object Promise]”
image

Adding async to the sort function still gets the table unsorted.

This is the altered code:

dv.table(
	["Paper", "Crit", "HL", "Terms", "Cases", "Mech", "Cits", "Figs", 
	"Extracts", "Refs", "EPlots", "RevEng", "Sum"],
	await Promise.all(
	pages
		.where(page => page.type == "paper")
		.mutate(async page => page.sum =
			  numListElem(page, "Critique") + numListElem(page, "Highlights") 
			+ numOf(page.term) + numOf(page.case) + numOf(page.mechanism) + numOf(page.paper)
			+ numFigures(page) 
			+ await numCallouts(page) 
			+ Math.abs(Math.round(Math.log(numOfRefs(page)+0.01)+0.5, 0))
			+ countPropertyValue1LD(page, "essential plots") * 10
			+ countPropertyValue1LD(page, "reverse engineering") * 20 )
		.sort(page => page.sum, 'desc')
		.map(async page => [
			dv.fileLink(page.file.name, false, dv.func.substring(page.file.name, 1, 13)),	
			numListElem(page, "Critique"),                      // section, list
			numListElem(page, "Highlights"),                    // section, list
			numOf(page.term),                                   // properties
			numOf(page.case),                                   // properties
			numOf(page.mechanism),                              // properties
			numOf(page.paper),                                  // properties
			numFigures(page),                                   // outlinks, embed
			await numCallouts(page),                            // regex
			numOfRefs(page, "References"),                      // inlinks, 1LD, filename, list
			countPropertyValue1LD(page, "essential plots"),     // inlinks, 1LD, property
			countPropertyValue1LD(page, "reverse engineering"), // inlinks, 1LD, property
			page.sum
			]
		 )
	  )
 )

The async and await don’t make things easier.

I’m trying to look into this, but there is some magic happening when combining the .mutate() and async/await. And it’s not the good kind of magic… I’m able to get the awaited result into the page object, but when it comes down to the mapping step it’s disappeared again. I’m wondering if it’s related to actually mutating something out of context, but I’ve not been able to figure out the details yet.

1 Like

Hi @sanyaissues,
I tried your method as well thinking that once the async value is written in data, it would made available as a hard value for the table operations. Still, for some reason, the table does not see the return of the values in data. Here is a simplified short version of the script:


function numOfRefs(page, str) {
	let filtered = page.file.inlinks.values
		.filter(p => p.path.contains(str))
	return filtered[0]?.path ?
	     dv.page(filtered[0]?.path).file.lists.length : 0
}

async function numCallouts(page) {
   const regex = />\s\[\!(\w+)\]\s(.+?)((\n>\s.*?)*)\n/ 
   const file = await app.vault.getAbstractFileByPath(page.file.path)
   const contents =  await app.vault.read(file)
   let count = 0
   for (const co of contents.match(new RegExp(regex, 'sg'))) {
	 count = count + 1
   }
   return count
}

let pages = dv.pages('"Sources"')

let data = 	
	await Promise.all(
	pages
		.where(page => page.type == "paper")
		.mutate(async page => page.countCallouts =  await numCallouts(page))
	)

console.log(data)

dv.table(["type", "Extracts", "NRefs"], 
		 data
		 .map(page => [
			 page.type,
			 page.countCallouts,
			 numOfRefs(page, "References")
		 ])

)

Printing data to the console works though:
image

I am able to see the countCallouts values for every paper:
image

But in the dataview table the column Extracts appears empty:

Very intriguing!

There should be a way to tell the async to write the results as hard values, and let go, so we could use them somewhere else.

Try this. Is working for me

function numOfRefs(page, str) {
	let filtered = page.file.inlinks.values
		.filter(p => p.path.contains(str))
	return filtered[0]?.path ?
	     dv.page(filtered[0]?.path).file.lists.length : 0
}

async function numCallouts(page) {
   const regex = />\s\[\!(\w+)\]\s(.+?)((\n>\s.*?)*)\n/ 
   const file = await app.vault.getAbstractFileByPath(page.file.path)
   const contents =  await app.vault.read(file)
   let count = 0
   for (const co of contents.match(new RegExp(regex, 'sg'))) {
	 count = count + 1
   }
   return count
}

let pages = dv.pages('"Sources"');

let data = await Promise.all(
    pages
        .where(page => page.type == "paper")
        .map(async page => {
            const callouts = await numCallouts(page);
            const refs = numOfRefs(page, "References"); 
            const sum = callouts + refs;
            return [
                page.type,
                callouts, 
                refs, 
                sum
            ];
        })
);


dv.table(["Type", "Extracts", "NRefs", "Sum"], data);

Yes, it works!
I am struggling to apply the sort by sum though.

let pages = dv.pages('"Sources"');

let data = await Promise.all(
    pages
        .where(page => page.type == "paper")
        .map(async page => {
            const callouts = await numCallouts(page);
            const refs = numOfRefs(page, "References"); 
            const sum = callouts + refs;
            return [
                page.type,
                callouts, 
                refs, 
                sum
            ];
        })
);

// Sort by ascendant order using the last column
data = data.sort((a, b) => a[data[0].length - 1] - b[data[0].length - 1]); 

// Sort by descendant order
//data = data.sort((a, b) => b[data[0].length - 1] - a[data[0].length - 1]); 

dv.table(["Type", "Extracts", "NRefs", "Sum"], data);

Try this for the moment. :sweat_smile:

1 Like

Excellent!
Works perfectly!

Thank you so much @sanyaissues

PS. I tried with mutate. It didn’t work. It wanted another Promise.all. Error with a parentheses. I also tried with the sort but inside the first data assignment.

1 Like

Great!

Maybe @holroy knows if there’s a way to apply sort() to the map(). I’m just a button-pusher :rofl:

1 Like

I have read in the Obsidian forum all there is about .mutate, async, Promise.all, .sort, but couldn’t find something applicable to this simple case.

This code, where I added the suggestions by @holroy, works 99%, with exception of the sort on sum. We are this close!

let pages = dv.pages('"Sources"')

dv.table(
	["Paper", "Crit", "HL", "Terms", "Cases", "Mech", "Cits", "Figs", 
	"Extracts", "Refs", "EPlots", "RevEng", "Sum"],
	await Promise.all(
	pages
		.where(page => page.type == "paper")
		.mutate(async page => page.sum =
			  numListElem(page, "Critique") + numListElem(page, "Highlights") 
			+ numOf(page.term) + numOf(page.case) + numOf(page.mechanism) + numOf(page.paper)
			+ numFigures(page) 
			+ await numCallouts(page)
			+ Math.abs(Math.round(Math.log(numOfRefs(page)+0.01)+0.5, 0))
			+ countPropertyValue1LD(page, "essential plots") * 10
			+ countPropertyValue1LD(page, "reverse engineering") * 20 )
		.map(async page => [
			dv.fileLink(page.file.name, false, dv.func.substring(page.file.name, 1, 13)),	
			numListElem(page, "Critique"),                      // section, list
			numListElem(page, "Highlights"),                    // section, list
			numOf(page.term),                                   // properties
			numOf(page.case),                                   // properties
			numOf(page.mechanism),                              // properties
			numOf(page.paper),                                  // properties
			numFigures(page),                                   // outlinks, embed
			await numCallouts(page),                            // regex
			numOfRefs(page, "References"),                      // inlinks, 1LD, filename, list
			countPropertyValue1LD(page, "essential plots"),     // inlinks, 1LD, property
			countPropertyValue1LD(page, "reverse engineering"), // inlinks, 1LD, property
			page.sum
			]
		 ).sort(page => page.sum, 'desc')
	  )
 )

It needs a little bit of knowledge on how sort works,

You need to sort before that last map, because afterwards you don’t which field is the sum.

Alternatively if you want it at the position it is, you need to do something like:

  .sort(row => row[12], "desc")

Note that it doesn’t matter what you call the variable, but I switched from page to row as a reminder that we’re not working with the page object anymore. Due to the map, we’re now working with a row where the index is the columns.

1 Like

@holroy,
Interestingly enough this sort would not work:

		.map(async page => 
		[
			dv.fileLink(page.file.name, false, dv.func.substring(page.file.name, 1, 13)),	
			numListElem(page, "Critique"),                      // section, list
			numListElem(page, "Highlights"),                    // section, list
			numOf(page.term),                                   // properties
			numOf(page.case),                                   // properties
			numOf(page.mechanism),                              // properties
			numOf(page.paper),                                  // properties
			numFigures(page),                                   // outlinks, embed
			await numCallouts(page),                            // regex
			numOfRefs(page, "References"),                      // inlinks, 1LD, filename, list
			countPropertyValue1LD(page, "essential plots"),     // inlinks, 1LD, property
			countPropertyValue1LD(page, "reverse engineering"), // inlinks, 1LD, property
			page.sum
			]
		 )
		 .sort(col => col[12], "desc")
	  )
 )

This other one, either:

let pages = dv.pages('"Sources"')

dv.table(
	["Paper", "Crit", "HL", "Terms", "Cases", "Mech", "Cits", "Figs", 
	"Extracts", "Refs", "EPlots", "RevEng", "Sum"],
	await Promise.all(
	pages
		.where(page => page.type == "paper")
		.mutate(async page => page.sum =
			  numListElem(page, "Critique") + numListElem(page, "Highlights") 
			+ numOf(page.term) + numOf(page.case) + numOf(page.mechanism) + numOf(page.paper)
			+ numFigures(page) 
			+ await numCallouts(page)
			+ Math.abs(Math.round(Math.log(numOfRefs(page)+0.01)+0.5, 0))
			+ countPropertyValue1LD(page, "essential plots") * 10
			+ countPropertyValue1LD(page, "reverse engineering") * 20 )
		.sort(p => p.sum, "desc")
		.map(async page => 
		 [
			dv.fileLink(page.file.name, false, dv.func.substring(page.file.name, 1, 13)),	
			numListElem(page, "Critique"),                      // section, list
			numListElem(page, "Highlights"),                    // section, list
			numOf(page.term),                                   // properties
			numOf(page.case),                                   // properties
			numOf(page.mechanism),                              // properties
			numOf(page.paper),                                  // properties
			numFigures(page),                                   // outlinks, embed
			await numCallouts(page),                            // regex
			numOfRefs(page, "References"),                      // inlinks, 1LD, filename, list
			countPropertyValue1LD(page, "essential plots"),     // inlinks, 1LD, property
			countPropertyValue1LD(page, "reverse engineering"), // inlinks, 1LD, property
			page.sum
			]
		 )
	  )
 )

Driving me crazy!

Hmm… There is something funky going on somewhere, and it’s most likely related to the promise/async stuff. And it’s really hard to debug this kind of stuff… I might be able to look a little more into it tomorrow.

The full query
```dataviewjs

const test = true 

function countPropertyValue1LD(page, propText) {
	return page.file.inlinks.values
		.filter(f => dv.func.contains(dv.page(f.path).related,
			 dv.func.link(propText))).length
}

function referenceLink(page, str) {
	let values = page.file.inlinks.values
	let filtered = values
		.filter(p => p.path.contains(str))
	return filtered
}

function numOfRefs(page, str) {
	let filtered = referenceLink(page, str)
	return filtered[0]?.path ?
	 dv.page(filtered[0]?.path).file.lists.length : 0
}

function numOf(property) {
	return !property ? 0 : typeof(property) == "string" 
					  ? 1 : property.length
}

function numFigures(page) {
	const embeds = page.file.outlinks
		.where(p => p.embed)
		.where(p => p.path.substr(p.path.length-3) == "png" )
	return (embeds.length)
}

function numListElem(page, section) {
	let values = page.file.lists.section.subpath.values
	return values ? 
	values.filter((w) => w === section).length : 0
}

const CALLOUT_REGEX = /^>\s*\[\!\w+\](.*?)\n(?:>.*?\n)*/gm

async function buildCalloutList(pages) {
  let extractList = {}
  
  return await
    Promise.all( pages.map(async page => {
      const file = app.vault.getAbstractFileByPath(page.file.path)
      const contents = await app.vault.read(file)
      const matches = contents.match( CALLOUT_REGEX) 
      return [page.file.path, matches ? matches.length : 0]
    }))   
    .then(values => {
      values.forEach(value => {
        extractList[value[0]] = value[1]
      })
      if (test) console.log("Promise.all.then there: ", extractList)  
      return extractList  
    })
    .catch(error => { dv.paragraph("~~~~\n" + error + "\n~~~~") })
}

async function main() { 
  // Build the complete set of notes we're working on
  let pages
  pages = dv.pages('"Sources"')
    .where(page => page.type == "paper")
  

  // Do the file read thingy on those pages 
  if (test) console.log("\n\nbefore")
  const numCallouts = await buildCalloutList(pages)
  if (test) console.log("after: ", Object.keys(numCallouts))

  // Build the result table (without await)
  const result = pages
    .mutate( page => {
      page.extracts = numCallouts[page.file.path]
      page.sum =
        numListElem(page, "Critique") + numListElem(page, "Highlights") 
        + numOf(page.term) + numOf(page.case) + numOf(page.mechanism) + numOf(page.paper)
        + page.figs
        + page.extracts
        + Math.abs(Math.round(Math.log(numOfRefs(page)+0.01)+0.5, 0))
        + countPropertyValue1LD(page, "essential plots") * 10
        + page.RevEng * 20
    })
    .sort(page => page.sum, 'asc')
    .map(page => [
      dv.fileLink(page.file.name, false, dv.func.substring(page.file.name, 1, 13)),
      numListElem(page, "Critique"),                      // section, list
      numListElem(page, "Highlights"),                    // section, list
      numOf(page.term),                                   // properties
      numOf(page.case),                                   // properties
      numOf(page.mechanism),                              // properties
      numOf(page.paper),                                  // properties
      numFigures(page),                                   // outlinks, embed
      page.extracts,                                      // regex
      numOfRefs(page, "References"),                      // inlinks, 1LD, filename, list
      countPropertyValue1LD(page, "essential plots"),     // inlinks, 1LD, property
      countPropertyValue1LD(page, "reverse engineering"), // inlinks, 1LD, property
      page.sum
    ])
    // .sort(row => row[12], 'desc')

  // Display the table, also without await
  dv.table(
    ["Paper", "Crit", "HL", "Terms", "Cases", "Mech", "Cits", "Figs",
     "Extracts", "Refs", "EPlots", "RevEng", "Sum"],
	 result)
}

// Make the entire thingy async...
(async() => {
  await main()
})()
 ```

Now I think I finally beaten it, and found a working, reliable solution. There are a few main changes done in this version compared to earlier versions:

  • I’ve built a dictionary before the main table result building, which encapsulates the stuff which needs to be awaited
  • In buildCalloutList I use a combination of await and .then, which isn’t really good coding practice, but there has been so many issues with this query, that when I got it working with this monstrosity I didn’t want to change it anymore
  • The entire script has been encapsulated within an IIFE (Immediately Invoked Function Expression) to allow for it to be awaited
  • Verified that both version of the sorting works as expected

I believe, but haven’t tested it thoroughly, that most of our issues all the way have been that at the outer layer we’ve not awaited the entirety of the process. This has led to promises being returned (and used later on), which has caused all of our mischief. The wrapping of main() has eliminated this issue in this particular case, I think…

2 Likes

Super!
It works very well!

I fixed few typos here and there on the function calls to get the same results.
Here is the final working version:

const test = true 

function countPropertyValue1LD(page, propText) {
	return page.file.inlinks.values
		.filter(f => dv.func.contains(dv.page(f.path).related,
			 dv.func.link(propText))).length
}

function referenceLink(page, str) {
	let values = page.file.inlinks.values
	let filtered = values
		.filter(p => p.path.contains(str))
	return filtered
}

function numOfRefs(page, str) {
	let filtered = referenceLink(page, str)
	return filtered[0]?.path ?
	 dv.page(filtered[0]?.path).file.lists.length : 0
}

function numOf(property) {
	return !property ? 0 : typeof(property) == "string" 
					  ? 1 : property.length
}

function numFigures(page) {
	const embeds = page.file.outlinks
		.where(p => p.embed)
		.where(p => p.path.substr(p.path.length-3) == "png" )
	return (embeds.length)
}

function numListElem(page, section) {
	let values = page.file.lists.section.subpath.values
	return values ? 
	values.filter((w) => w === section).length : 0
}

const CALLOUT_REGEX = />\s\[\!(\w+)\]\s(.+?)((\n>\s.*?)*)\n/sg 

async function buildCalloutList(pages) {
  let extractList = {}
  
  return await
    Promise.all( pages.map(async page => {
      const file = app.vault.getAbstractFileByPath(page.file.path)
      const contents = await app.vault.read(file)
      const matches = contents.match( CALLOUT_REGEX) 
      return [page.file.path, matches ? matches.length : 0]
    }))   
    .then(values => {
      values.forEach(value => {
        extractList[value[0]] = value[1]
      })
      if (test) console.log("Promise.all.then there: ", extractList)  
      return extractList  
    })
    .catch(error => { dv.paragraph("~~~~\n" + error + "\n~~~~") })
}


async function main() { 
  // Build the complete set of notes we're working on
  let pages
  pages = dv.pages('"Sources"')
    .where(page => page.type == "paper")
  
  // Do the file read thingy on those pages 
  if (test) console.log("\n\nbefore")
  const numCallouts = await buildCalloutList(pages)
  if (test) console.log("after: ", Object.keys(numCallouts))

  // Build the result table (without await)
  const result = pages
    .mutate( page => {
      page.extracts = numCallouts[page.file.path]
      page.sum =
        numListElem(page, "Critique") + numListElem(page, "Highlights") 
        + numOf(page.term) + numOf(page.case) + numOf(page.mechanism) + numOf(page.paper)
        + numFigures(page)
        + page.extracts
        + Math.abs(Math.round(Math.log(numOfRefs(page, "References"))+0.5, 0))
        + countPropertyValue1LD(page, "essential plots") * 10
        + countPropertyValue1LD(page, "reverse engineering") * 20
    })
    .sort(page => page.sum, 'desc')
    .map(page => [
      dv.fileLink(page.file.name, false, dv.func.substring(page.file.name, 1, 13)),
      numListElem(page, "Critique"),                      // section, list
      numListElem(page, "Highlights"),                    // section, list
      numOf(page.term),                                   // properties
      numOf(page.case),                                   // properties
      numOf(page.mechanism),                              // properties
      numOf(page.paper),                                  // properties
      numFigures(page),                                   // outlinks, embed
      page.extracts,                                      // regex
      numOfRefs(page, "References"),                      // inlinks, 1LD, filename, list
      countPropertyValue1LD(page, "essential plots"),     // inlinks, 1LD, property
      countPropertyValue1LD(page, "reverse engineering"), // inlinks, 1LD, property
      page.sum
    ])

  // Display the table, also without await
  dv.table(
    ["Paper", "Crit", "HL", "Terms", "Cases", "Mech", "Cits", "Figs",
     "Extracts", "Refs", "EPlots", "RevEng", "Sum"], result)
}

// Make the entire thingy async...
(async() => {
  await main()
}) ()

Definitely, this level of JavaScript is out of my league.
The good thing that is that I learned a lot with this async thing.

Thank you very much @holroy.

1 Like