Skip to content

Commit

Permalink
feat: add csv-table directive
Browse files Browse the repository at this point in the history
  • Loading branch information
agoose77 committed Apr 17, 2024
1 parent e304b65 commit 4b0da69
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 1 deletion.
6 changes: 6 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/myst-directives/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
},
"dependencies": {
"classnames": "^2.3.2",
"csv-parse": "^5.5.5",
"js-yaml": "^4.1.0",
"myst-common": "^1.2.0",
"myst-spec-ext": "^1.2.0",
Expand Down
94 changes: 93 additions & 1 deletion packages/myst-directives/src/table.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { DirectiveSpec, DirectiveData, GenericNode } from 'myst-common';
import type { DirectiveSpec, DirectiveData, DirectiveContext, GenericNode } from 'myst-common';
import { fileError, normalizeLabel, RuleId } from 'myst-common';
import type { VFile } from 'vfile';
import { parse } from 'csv-parse/sync';

export const tableDirective: DirectiveSpec = {
name: 'table',
Expand Down Expand Up @@ -162,3 +163,94 @@ export const listTableDirective: DirectiveSpec = {
return [container];
},
};

export const csvTableDirective: DirectiveSpec = {
name: 'csv-table',
arg: {
type: 'myst',
},
options: {
label: {
type: String,
alias: ['name'],
},
'header-rows': {
type: Number,
// nonnegative int
},
class: {
type: String,
// class_option: list of strings?
doc: `CSS classes to add to your table. Special classes include:
- \`full-width\`: changes the table environment to cover two columns in LaTeX`,
},
align: {
type: String,
// choice(['left', 'center', 'right'])
},
delim: {
type: String,
},
escape: {
type: String,
},
keepspace: {
type: Boolean,
},
quote: {
type: String,
},
},
body: {
type: String,
required: true,
},
run(data: DirectiveData, vfile: VFile, ctx: DirectiveContext): GenericNode[] {
const delimiter = (data.options?.delimiter ?? ',') as string;
const records = parse(data.body as string, {
delimiter,
ltrim: !data.options?.keepspace,
escape: (data.options?.escape ?? delimiter) as string,
quote: (data.options?.quote ?? '"') as string,
});

const { label, identifier } = normalizeLabel(data.options?.label as string | undefined) || {};

let headerCount = (data.options?.['header-rows'] as number) || 0;
const rows = records.map((record: any, recordIndex: number) => {
const cells = record.map((cell: string) => {
const rawCells = ctx.parseMyst(cell, recordIndex);
if (!(rawCells.length === 1 && rawCells[0].type === 'paragraph')) {
throw new Error(`Expected a single paragraph node, encountered ${rawCells[0].type}`);
}
return {
type: 'tableCell',
header: headerCount > 0 ? true : undefined,
children: rawCells[0].children,
};
});
headerCount -= 1;
// Parsing produes multiple nodes
return {
type: 'tableRow',
children: cells,
};
});
const table = {
type: 'table',
align: data.options?.align,
children: rows,
};
const container = {
type: 'container',
kind: 'table',
identifier: identifier,
label: label,
class: data.options?.class,
children: [...(data.arg as GenericNode[]), table],
};

return [container];
},
};

0 comments on commit 4b0da69

Please sign in to comment.