markdown-it-adv-table 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,9 +1,5 @@
1
1
  import type { StateBlock } from "markdown-it/index.js";
2
2
  import { TableAttr } from "./table.js";
3
- /**
4
- * AdvTableParser delegates parsing to the appropriate parser
5
- * based on the format option specified.
6
- */
7
3
  export declare class AdvTableParser {
8
4
  readonly attrs: TableAttr;
9
5
  readonly params: string;
@@ -1,10 +1,6 @@
1
1
  import { CsvTableParser } from "./csv-table.js";
2
2
  import { FlatTableParser } from "./flat-table.js";
3
3
  import { TableSpec } from "./table.js";
4
- /**
5
- * AdvTableParser delegates parsing to the appropriate parser
6
- * based on the format option specified.
7
- */
8
4
  export class AdvTableParser {
9
5
  attrs;
10
6
  params;
@@ -28,7 +28,6 @@ export class CsvTableParser {
28
28
  for (let col = 0; col < cells[row].length; col++) {
29
29
  const itoken = istate.push("text", "", 0);
30
30
  itoken.content = cells[row][col];
31
- // manually assign inline token to disable being inline-processed.
32
31
  builder.insertCell(state => {
33
32
  const token = state.push("inline", "", 0);
34
33
  token.content = "";
@@ -49,7 +48,6 @@ export class CsvTableParser {
49
48
  const lines = text.split("\n");
50
49
  let result = [];
51
50
  for (const line of lines) {
52
- // skip empty line
53
51
  if (line.trim().length === 0) {
54
52
  continue;
55
53
  }
@@ -66,7 +64,6 @@ export class CsvTableParser {
66
64
  }
67
65
  else if (Lexer.cmp(cp, delim)) {
68
66
  lexer.skipWhitespace();
69
- // if next letter is "," insert empty column
70
67
  if (Lexer.cmp(lexer.peekNext(), delim)) {
71
68
  columns.push("");
72
69
  }
@@ -2,9 +2,6 @@
2
2
  export function createDebug(namespace) {
3
3
  const nsList = process.env.DEBUG?.split(",").map((s) => s.trim()) ?? [];
4
4
  const isEnabled = nsList.some((ns) => {
5
- // if (ns === "*") { // Intentionally disabled because this output
6
- // return true; // should not be mixed with other libraries.
7
- // }
8
5
  if (ns === namespace) {
9
6
  return true;
10
7
  }
@@ -1,8 +1,4 @@
1
1
  import type { StateBlock } from "markdown-it/index.js";
2
2
  import type { RuleBlock } from "markdown-it/lib/parser_block.mjs";
3
3
  export type Parser = (info: string, state: StateBlock, startLine: number, endLine: number) => void;
4
- /**
5
- * Parse fenced code block and if the name matches, the content is passed to
6
- * the custom parser.
7
- */
8
4
  export declare function fence_custom(names: string | string[], parser: Parser): RuleBlock;
@@ -1,7 +1,3 @@
1
- /**
2
- * Parse fenced code block and if the name matches, the content is passed to
3
- * the custom parser.
4
- */
5
1
  export function fence_custom(names, parser) {
6
2
  if (typeof names === "string") {
7
3
  names = [names];
@@ -9,7 +5,6 @@ export function fence_custom(names, parser) {
9
5
  return (state, startLine, endLine, silent) => {
10
6
  let pos = state.bMarks[startLine] + state.tShift[startLine];
11
7
  let max = state.eMarks[startLine];
12
- // if it's indented more than 3 spaces, it should be a code block
13
8
  if (state.sCount[startLine] - state.blkIndent >= 4) {
14
9
  return false;
15
10
  }
@@ -17,10 +12,9 @@ export function fence_custom(names, parser) {
17
12
  return false;
18
13
  }
19
14
  const marker = state.src.charCodeAt(pos);
20
- if (marker !== 0x7E /* ~ */ && marker !== 0x60 /* ` */) {
15
+ if (marker !== 0x7E && marker !== 0x60) {
21
16
  return false;
22
17
  }
23
- // scan marker length
24
18
  let mem = pos;
25
19
  pos = state.skipChars(pos, marker);
26
20
  let len = pos - mem;
@@ -29,7 +23,7 @@ export function fence_custom(names, parser) {
29
23
  }
30
24
  const markup = state.src.slice(mem, pos);
31
25
  const params = state.src.slice(pos, max);
32
- if (marker === 0x60 /* ` */) {
26
+ if (marker === 0x60) {
33
27
  if (params.indexOf(String.fromCharCode(marker)) >= 0) {
34
28
  return false;
35
29
  }
@@ -37,47 +31,36 @@ export function fence_custom(names, parser) {
37
31
  if (!names.some(name => params.startsWith(name))) {
38
32
  return false;
39
33
  }
40
- // Since start is found, we can report success here in validation mode
41
34
  if (silent) {
42
35
  return true;
43
36
  }
44
- // search end of block
45
37
  let nextLine = startLine;
46
38
  let haveEndMarker = false;
47
39
  for (;;) {
48
40
  nextLine++;
49
41
  if (nextLine >= endLine) {
50
- // unclosed block should be autoclosed by end of document.
51
- // also block seems to be autoclosed by end of parent
52
42
  break;
53
43
  }
54
44
  pos = mem = state.bMarks[nextLine] + state.tShift[nextLine];
55
45
  max = state.eMarks[nextLine];
56
46
  if (pos < max && state.sCount[nextLine] < state.blkIndent) {
57
- // non-empty line with negative indent should stop the list:
58
- // - ```
59
- // test
60
47
  break;
61
48
  }
62
49
  if (state.src.charCodeAt(pos) !== marker) {
63
50
  continue;
64
51
  }
65
52
  if (state.sCount[nextLine] - state.blkIndent >= 4) {
66
- // closing fence should be indented less than 4 spaces
67
53
  continue;
68
54
  }
69
55
  pos = state.skipChars(pos, marker);
70
- // closing code fence must be at least as long as the opening one
71
56
  if (pos - mem < len) {
72
57
  continue;
73
58
  }
74
- // make sure tail has spaces only
75
59
  pos = state.skipSpaces(pos);
76
60
  if (pos < max) {
77
61
  continue;
78
62
  }
79
63
  haveEndMarker = true;
80
- // found!
81
64
  break;
82
65
  }
83
66
  len = state.sCount[startLine];
@@ -1,24 +1,13 @@
1
1
  import type { StateBlock } from "markdown-it/index.js";
2
2
  import { CellAttr, TableSpec } from "./table.js";
3
- /**
4
- * FlatTableParser parses the flat-table syntax.
5
- */
6
3
  export declare class FlatTableParser {
7
4
  private _tableSpec;
8
5
  constructor(tableSpec: TableSpec);
9
6
  static new(params: string, state: StateBlock, startLine: number, endLine: number): FlatTableParser;
10
- /**
11
- * Parse custom table syntax into tokens.
12
- *
13
- * @param state markdown-it parser state
14
- * @param startLine the first line which contains the table syntax.
15
- * @param endLine the last line which contains the table syntax.
16
- */
17
7
  parse(state: StateBlock, startLine: number, endLine: number): void;
18
8
  getline(state: StateBlock, lineNumber: number): string;
19
9
  static getCellIndent(state: StateBlock, line: string): number;
20
10
  static isCellStart(line: string): boolean;
21
- /** extract cellspec from line */
22
11
  static cellspec(line: string): string;
23
12
  static parseCellspec(line: string): CellAttr;
24
13
  static inferColCount(state: StateBlock, lineStart: number, lineEnd: number): number;
@@ -1,8 +1,5 @@
1
1
  import { TableBuilder } from "./table-builder.js";
2
2
  import { TableSpec } from "./table.js";
3
- /**
4
- * FlatTableParser parses the flat-table syntax.
5
- */
6
3
  export class FlatTableParser {
7
4
  _tableSpec;
8
5
  constructor(tableSpec) {
@@ -16,33 +13,22 @@ export class FlatTableParser {
16
13
  const tableSpec = new TableSpec(attr);
17
14
  return new FlatTableParser(tableSpec);
18
15
  }
19
- /**
20
- * Parse custom table syntax into tokens.
21
- *
22
- * @param state markdown-it parser state
23
- * @param startLine the first line which contains the table syntax.
24
- * @param endLine the last line which contains the table syntax.
25
- */
26
16
  parse(state, startLine, endLine) {
27
17
  const builder = new TableBuilder(state, this._tableSpec);
28
18
  builder.startTable();
29
19
  let currentLine = startLine;
30
20
  while (currentLine < endLine) {
31
21
  const line = state.getLines(currentLine, currentLine + 1, state.blkIndent, false);
32
- // skip empty line
33
22
  if (line.trim().length === 0) {
34
23
  currentLine++;
35
24
  continue;
36
25
  }
37
- // cell starter
38
26
  if (FlatTableParser.isCellStart(line)) {
39
- // find cell content range
40
27
  const cellStart = currentLine;
41
28
  while (currentLine + 1 < endLine && !FlatTableParser.isCellStart(this.getline(state, currentLine + 1))) {
42
29
  currentLine++;
43
30
  }
44
31
  const cellEnd = currentLine;
45
- // parse cell content as document
46
32
  const md = state.md;
47
33
  const cellIndent = FlatTableParser.getCellIndent(state, line);
48
34
  const cellSpec = FlatTableParser.cellspec(line);
@@ -74,7 +60,7 @@ export class FlatTableParser {
74
60
  }
75
61
  static getCellIndent(state, line) {
76
62
  const cellStart = line.search(/\|/);
77
- const numSpaces = line.slice(cellStart + 1).search(/\S|$/); // number of spaces between symbol and text
63
+ const numSpaces = line.slice(cellStart + 1).search(/\S|$/);
78
64
  const userIndent = Math.max(0, Math.min(1 + numSpaces, 4));
79
65
  return state.blkIndent + userIndent;
80
66
  }
@@ -85,7 +71,6 @@ export class FlatTableParser {
85
71
  return true;
86
72
  return false;
87
73
  }
88
- /** extract cellspec from line */
89
74
  static cellspec(line) {
90
75
  const match = /^((r\d+|c\d+|\<|\^|\>|h)*)\|/.exec(line);
91
76
  if (match === null) {
@@ -144,7 +129,6 @@ export class FlatTableParser {
144
129
  }
145
130
  }
146
131
  static inferColCount(state, lineStart, lineEnd) {
147
- // TBD: does not handle colspan, rowspan
148
132
  let contLen = 0;
149
133
  let contLenMax = 0;
150
134
  for (let line = lineStart; line < lineEnd; line++) {
@@ -6,39 +6,22 @@ export declare class Lexer {
6
6
  input: string;
7
7
  pos: number;
8
8
  constructor(input: string);
9
- /** Return current char */
10
9
  get char(): string;
11
- /** Return remaining string */
12
10
  get str(): string;
13
- /** Return current charcode */
14
11
  peek(): number;
15
- /** Return next charcode */
16
12
  peekNext(): number;
17
- /** test against upcoming string */
18
13
  match(ptn: string): boolean;
19
- /** Return current charcode and advance cursor by one */
20
14
  next(): number;
21
- /** Return true if cursor is at the end of input */
22
15
  eof(): boolean;
23
- /** Peek letters and skip input */
24
16
  skip(re: RegExp): void;
25
- /** Skip whitespaces */
26
17
  skipWhitespace(): void;
27
- /** Consume single letter */
28
18
  consume(): string;
29
- /** Consume a sequence of letters */
30
19
  consumeRe(re: RegExp): string;
31
- /** Consume word (/^[a-zA-Z_][a-zA-Z0-9_]+/) */
32
20
  consumeWord(): string;
33
- /** Consume quote enclosed literal */
34
21
  consumeLiteral(quote: string): string;
35
- /** Return codepoint of a letter, or EOF if input string is empty */
36
22
  static cp(ch: string): number;
37
- /** Return true if the codepoint matches the string */
38
23
  static cmp(cp: number, ch: string): boolean;
39
- /** Return true if the codepoint matches our EOF number */
40
24
  static isEOF(cp: number): boolean;
41
- /** Return true if the codepint is likely to be whitespace */
42
25
  static isWhitespace(cp: number): boolean;
43
26
  static isAlphabet(cp: number): boolean;
44
27
  static isNumber(cp: number): boolean;
@@ -9,54 +9,43 @@ export class Lexer {
9
9
  this.input = input;
10
10
  this.pos = 0;
11
11
  }
12
- /** Return current char */
13
12
  get char() {
14
13
  return this.input[this.pos] || Lexer.EMPTY;
15
14
  }
16
- /** Return remaining string */
17
15
  get str() {
18
16
  return this.input.slice(this.pos);
19
17
  }
20
- /** Return current charcode */
21
18
  peek() {
22
19
  return this.input.codePointAt(this.pos) || Lexer.EOF;
23
20
  }
24
- /** Return next charcode */
25
21
  peekNext() {
26
22
  return this.input.codePointAt(this.pos + 1) || Lexer.EOF;
27
23
  ;
28
24
  }
29
- /** test against upcoming string */
30
25
  match(ptn) {
31
26
  return this.str.startsWith(ptn);
32
27
  }
33
- /** Return current charcode and advance cursor by one */
34
28
  next() {
35
29
  const char = this.peek();
36
30
  this.pos++;
37
31
  return char;
38
32
  }
39
- /** Return true if cursor is at the end of input */
40
33
  eof() {
41
34
  return this.pos >= this.input.length;
42
35
  }
43
- /** Peek letters and skip input */
44
36
  skip(re) {
45
37
  while (re.test(this.char)) {
46
38
  this.pos++;
47
39
  }
48
40
  }
49
- /** Skip whitespaces */
50
41
  skipWhitespace() {
51
42
  this.skip(Lexer.WHITESPACE);
52
43
  }
53
- /** Consume single letter */
54
44
  consume() {
55
45
  const result = this.char;
56
46
  this.pos++;
57
47
  return result;
58
48
  }
59
- /** Consume a sequence of letters */
60
49
  consumeRe(re) {
61
50
  const match = re.exec(this.str);
62
51
  if (!match) {
@@ -66,11 +55,9 @@ export class Lexer {
66
55
  this.pos += word.length;
67
56
  return word;
68
57
  }
69
- /** Consume word (/^[a-zA-Z_][a-zA-Z0-9_]+/) */
70
58
  consumeWord() {
71
59
  return this.consumeRe(/^[a-zA-Z_][a-zA-Z0-9_]+/);
72
60
  }
73
- /** Consume quote enclosed literal */
74
61
  consumeLiteral(quote) {
75
62
  const q = quote.codePointAt(0);
76
63
  const escape = "\\".codePointAt(0);
@@ -94,7 +81,6 @@ export class Lexer {
94
81
  }
95
82
  }
96
83
  else if (cp === Lexer.EOF) {
97
- // unenclosed quote
98
84
  break;
99
85
  }
100
86
  else {
@@ -103,30 +89,22 @@ export class Lexer {
103
89
  }
104
90
  return String.fromCodePoint(...result);
105
91
  }
106
- /** Return codepoint of a letter, or EOF if input string is empty */
107
92
  static cp(ch) {
108
93
  return ch.codePointAt(0) || Lexer.EOF;
109
94
  }
110
- /** Return true if the codepoint matches the string */
111
95
  static cmp(cp, ch) {
112
96
  return cp === ch.codePointAt(0);
113
97
  }
114
- /** Return true if the codepoint matches our EOF number */
115
98
  static isEOF(cp) {
116
99
  return cp === Lexer.EOF;
117
100
  }
118
- /** Return true if the codepint is likely to be whitespace */
119
101
  static isWhitespace(cp) {
120
- // return this.WHITESPACE.test(String.fromCodePoint(cp));
121
102
  return cp === " ".codePointAt(0) || cp === "\t".codePointAt(0);
122
103
  }
123
104
  static isAlphabet(cp) {
124
- // return cp >= "a".codePointAt(0)! && cp <= "z".codePointAt(0)! ||
125
- // cp >= "A".codePointAt(0)! && cp <= "Z".codePointAt(0)!;
126
105
  return (cp >= 97 && cp <= 122) || (cp >= 65 && cp <= 90);
127
106
  }
128
107
  static isNumber(cp) {
129
- // return cp >= "0".codePointAt(0)! && cp <= "9".codePointAt(0)!;
130
108
  return cp >= 48 && cp <= 57;
131
109
  }
132
110
  static isAlnum(cp) {
@@ -8,19 +8,5 @@ type DeepMerged<T, U> = {
8
8
  };
9
9
  export declare function isPrimitive(value: unknown): value is Primitive;
10
10
  export declare function isFunction(value: unknown): value is Function;
11
- /**
12
- * merge, a deepmerge implementation.
13
- *
14
- * - target immutable
15
- * - prototype aware
16
- * - circular ref aware
17
- * - replace array (no-join)
18
- * - ignore unenumerable properties
19
- * - ignore undefined
20
- *
21
- * @param target target type
22
- * @param source source type
23
- * @returns merged object (target + source)
24
- */
25
11
  export declare function merge<T, U>(target: Partial<T>, source?: Partial<U>): DeepMerged<T, U>;
26
12
  export {};
@@ -10,20 +10,6 @@ export function isPrimitive(value) {
10
10
  export function isFunction(value) {
11
11
  return typeof value === "function";
12
12
  }
13
- /**
14
- * merge, a deepmerge implementation.
15
- *
16
- * - target immutable
17
- * - prototype aware
18
- * - circular ref aware
19
- * - replace array (no-join)
20
- * - ignore unenumerable properties
21
- * - ignore undefined
22
- *
23
- * @param target target type
24
- * @param source source type
25
- * @returns merged object (target + source)
26
- */
27
13
  export function merge(target, source) {
28
14
  const seen = new WeakMap();
29
15
  function _merge(target, source) {
@@ -42,7 +28,6 @@ export function merge(target, source) {
42
28
  const result = { ...target };
43
29
  seen.set(source, result);
44
30
  for (const key of Object.keys(source)) {
45
- // Skip dangerous keys
46
31
  if (key === "__proto__" || key === "constructor" || key === "prototype") {
47
32
  continue;
48
33
  }
@@ -55,7 +40,7 @@ export function merge(target, source) {
55
40
  return result;
56
41
  }
57
42
  else {
58
- return undefined; // ?
43
+ return undefined;
59
44
  }
60
45
  }
61
46
  const merged = _merge(target, source);
@@ -6,9 +6,6 @@ interface ITableBuilder {
6
6
  endTable(): void;
7
7
  insertCell(fn: TokenAppendor, attr?: CellAttr): void;
8
8
  }
9
- /**
10
- * Constructs a table token stream
11
- */
12
9
  export declare class TableBuilder implements ITableBuilder {
13
10
  readonly state: StateBlock;
14
11
  readonly tableSpec: TableSpec;
@@ -1,8 +1,5 @@
1
1
  import { debug } from "./debug.js";
2
2
  import { CellState } from "./table.js";
3
- /**
4
- * Constructs a table token stream
5
- */
6
3
  export class TableBuilder {
7
4
  state;
8
5
  tableSpec;
@@ -15,9 +15,6 @@ export type CellAttr = {
15
15
  rowspan?: number;
16
16
  header?: boolean;
17
17
  };
18
- /**
19
- * TableSpec keeps table attributes
20
- */
21
18
  export declare class TableSpec {
22
19
  readonly attr: TableAttr;
23
20
  readonly classes: string[];
@@ -30,9 +27,6 @@ export declare class TableSpec {
30
27
  static parseInfoString(info: string): TableAttr;
31
28
  static awareKeys(): TableAttrKeys[];
32
29
  }
33
- /**
34
- * ColSpecs keeps all column specifications
35
- */
36
30
  export declare class ColSpecs {
37
31
  readonly numCols: number;
38
32
  readonly specs: readonly ColumnAttr[];
@@ -40,9 +34,7 @@ export declare class ColSpecs {
40
34
  colSpec(col: number): ColumnAttr;
41
35
  colWidth(col: number): number;
42
36
  colWidthRatio(col: number): number;
43
- /** Forcefully re-initailize this instance. */
44
37
  lazyInit(cols: number): void;
45
- /** Parse colspec for single column */
46
38
  static parseColSpec(spec: string): ColumnAttr;
47
39
  }
48
40
  export declare class TableCell {
@@ -58,9 +50,6 @@ export declare class TableCell {
58
50
  isIn(row: number, col: number, rspan: number, cspan: number): boolean;
59
51
  contains(row: number, col: number): boolean;
60
52
  }
61
- /**
62
- * A state machine to track cell position and its attributes
63
- */
64
53
  export declare class CellState {
65
54
  private static readonly _initialPos;
66
55
  private readonly _tableSpec;
@@ -73,28 +62,15 @@ export declare class CellState {
73
62
  set row(num: number);
74
63
  get col(): number;
75
64
  set col(num: number);
76
- /** Starting from the top-left cell, find the next free cell. **/
77
65
  next(): {
78
66
  row: number;
79
67
  col: number;
80
68
  };
81
- /**
82
- * Get cell attribute. If the cell is spanned by the other, it will return
83
- * the belonging cell. Returns undefined if no attribute is set.
84
- */
85
69
  get(row: number, col: number): TableCell | undefined;
86
- /**
87
- * Set cell attribute. If the cell is already spanned by the other,
88
- * it will update the belonging cell. Modifying the span size will
89
- * wipe attributes from the cells being affected.
90
- */
91
70
  set(row: number, col: number, attr: CellAttr): void;
92
71
  wipe(row: number, col: number, rowspan: number, colspan: number, keepOrigin?: boolean): void;
93
- /** Return true if this cell is spanned (includes self spanning) */
94
72
  isSpanned(row: number, col: number): boolean;
95
- /** Return the cell which covers the given cell (excludes self span)*/
96
73
  spannedBy(row: number, col: number): TableCell | undefined;
97
- /** Return true if this cell is the left most cell **/
98
74
  isLeftMost(row: number, col: number): boolean;
99
75
  isRightMost(row: number, col: number): boolean;
100
76
  isRowFirst(row: number, col: number): boolean;
@@ -1,7 +1,4 @@
1
1
  import { Lexer, unwrapLiteral } from "./lexer.js";
2
- /**
3
- * TableSpec keeps table attributes
4
- */
5
2
  export class TableSpec {
6
3
  attr;
7
4
  classes;
@@ -23,7 +20,7 @@ export class TableSpec {
23
20
  .split(",")
24
21
  .map((s) => s.trim())
25
22
  .filter(s => s.length > 0)
26
- .filter((s, i, arr) => arr.indexOf(s) === i); // uniq
23
+ .filter((s, i, arr) => arr.indexOf(s) === i);
27
24
  }
28
25
  static parseInfoString(info) {
29
26
  const lexer = new Lexer(info);
@@ -47,7 +44,6 @@ export class TableSpec {
47
44
  break;
48
45
  }
49
46
  else {
50
- // unknown symbol?
51
47
  tokens.push(lexer.consume());
52
48
  }
53
49
  }
@@ -63,12 +59,10 @@ export class TableSpec {
63
59
  result[key] = value;
64
60
  }
65
61
  else {
66
- // ignore unknown token
67
62
  consume();
68
63
  }
69
64
  }
70
65
  return result;
71
- /** consume one token from token stream */
72
66
  function consume(text) {
73
67
  const token = tokens[lc];
74
68
  if (text && token !== text) {
@@ -90,17 +84,11 @@ export class TableSpec {
90
84
  return Object.keys(k);
91
85
  }
92
86
  }
93
- /**
94
- * ColSpecs keeps all column specifications
95
- */
96
87
  export class ColSpecs {
97
88
  numCols;
98
89
  specs;
99
90
  constructor(colspec) {
100
91
  if (colspec.startsWith("\"") || colspec.includes(",")) {
101
- // colspec must be "1,1,1" not 1,1,1
102
- // we can try parse 1,1,1 .... but since this is an invalid syntax,
103
- // the parser won't recognize unwrapped commma-separated values.
104
92
  const specs = unwrapLiteral(colspec, "\"").split(",");
105
93
  this.numCols = Math.max(1, specs.length);
106
94
  this.specs = specs.map(ColSpecs.parseColSpec);
@@ -131,12 +119,10 @@ export class ColSpecs {
131
119
  }
132
120
  return this.colWidth(col) / totalWidth;
133
121
  }
134
- /** Forcefully re-initailize this instance. */
135
122
  lazyInit(cols) {
136
123
  this.numCols = cols;
137
124
  this.specs = Array(cols).fill({});
138
125
  }
139
- /** Parse colspec for single column */
140
126
  static parseColSpec(spec) {
141
127
  let pos = 0;
142
128
  const attr = {};
@@ -207,9 +193,6 @@ export class TableCell {
207
193
  this.col <= col && this.col + this.colspan > col);
208
194
  }
209
195
  }
210
- /**
211
- * A state machine to track cell position and its attributes
212
- */
213
196
  export class CellState {
214
197
  static _initialPos = [-1, -1];
215
198
  _tableSpec;
@@ -238,7 +221,6 @@ export class CellState {
238
221
  set col(num) {
239
222
  this._pos[1] = num;
240
223
  }
241
- /** Starting from the top-left cell, find the next free cell. **/
242
224
  next() {
243
225
  if (this.row === -1) {
244
226
  this.row = 0;
@@ -258,10 +240,6 @@ export class CellState {
258
240
  col: this.col,
259
241
  };
260
242
  }
261
- /**
262
- * Get cell attribute. If the cell is spanned by the other, it will return
263
- * the belonging cell. Returns undefined if no attribute is set.
264
- */
265
243
  get(row, col) {
266
244
  for (const span of this._cells) {
267
245
  if (span.contains(row, col)) {
@@ -270,11 +248,6 @@ export class CellState {
270
248
  }
271
249
  return undefined;
272
250
  }
273
- /**
274
- * Set cell attribute. If the cell is already spanned by the other,
275
- * it will update the belonging cell. Modifying the span size will
276
- * wipe attributes from the cells being affected.
277
- */
278
251
  set(row, col, attr) {
279
252
  for (const span of this._cells) {
280
253
  if (span.contains(row, col)) {
@@ -292,7 +265,6 @@ export class CellState {
292
265
  : c.isIn(row, col, rowspan, colspan);
293
266
  });
294
267
  }
295
- /** Return true if this cell is spanned (includes self spanning) */
296
268
  isSpanned(row, col) {
297
269
  for (const span of this._cells) {
298
270
  if (!span.is(row, col) && span.contains(row, col)) {
@@ -301,7 +273,6 @@ export class CellState {
301
273
  }
302
274
  return false;
303
275
  }
304
- /** Return the cell which covers the given cell (excludes self span)*/
305
276
  spannedBy(row, col) {
306
277
  for (const span of this._cells) {
307
278
  if (!span.is(row, col) && span.contains(row, col)) {
@@ -310,10 +281,9 @@ export class CellState {
310
281
  }
311
282
  return undefined;
312
283
  }
313
- /** Return true if this cell is the left most cell **/
314
284
  isLeftMost(row, col) {
315
285
  if (col <= 0) {
316
- return true; // left most, or out of range
286
+ return true;
317
287
  }
318
288
  else {
319
289
  const span = this.get(row, col);
@@ -322,7 +292,7 @@ export class CellState {
322
292
  }
323
293
  isRightMost(row, col) {
324
294
  if (col >= this.numCols - 1) {
325
- return true; // right most, or out of range
295
+ return true;
326
296
  }
327
297
  else {
328
298
  const span = this.get(row, col);
@@ -333,21 +303,17 @@ export class CellState {
333
303
  if (col < 0)
334
304
  return false;
335
305
  if (col === 0) {
336
- // If this cell is spanned by the other cell, it is not a row starter
337
306
  return this.spannedBy(row, col) === undefined;
338
307
  }
339
- // if this cell is spanned by the other cell,
340
- // always return false.
341
308
  if (this.spannedBy(row, col) !== undefined) {
342
309
  return false;
343
310
  }
344
311
  while (col > 0) {
345
312
  const span = this.spannedBy(row, col - 1);
346
- // recursively check left cell
347
313
  if (span !== undefined) {
348
314
  if (span.col < col) {
349
315
  if (span.row === row) {
350
- return false; // spanning cell is in the same row
316
+ return false;
351
317
  }
352
318
  else {
353
319
  col = span.col;
@@ -361,24 +327,19 @@ export class CellState {
361
327
  return false;
362
328
  }
363
329
  }
364
- // all cells in left are spanned, so this cell is the row-first cell
365
330
  return true;
366
331
  }
367
332
  isRowLast(row, col) {
368
333
  if (col >= this.numCols)
369
334
  return false;
370
335
  if (col === this.numCols - 1) {
371
- // If this cell is spanned by the other cell, it is not a row closer.
372
336
  return this.spannedBy(row, col) === undefined;
373
337
  }
374
- // if this cell is spanned by the other cell,
375
- // always return false.
376
338
  if (this.spannedBy(row, col) !== undefined) {
377
339
  return false;
378
340
  }
379
341
  while (col < this.numCols - 1) {
380
342
  const span = this.spannedBy(row, col + 1);
381
- // recursively check right cell
382
343
  if (span !== undefined) {
383
344
  if (span.endcol > col) {
384
345
  col = span.endcol;
@@ -391,7 +352,6 @@ export class CellState {
391
352
  return false;
392
353
  }
393
354
  }
394
- // all cells in right are spanned, so this cell is the row-last cell
395
355
  return true;
396
356
  }
397
357
  }
package/package.json CHANGED
@@ -1,13 +1,12 @@
1
1
  {
2
2
  "name": "markdown-it-adv-table",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Markdown syntax extension for better table support",
5
5
  "keywords": [
6
6
  "markdown",
7
7
  "markdown-it",
8
8
  "markdown-it-plugin",
9
- "table",
10
- "csv"
9
+ "table"
11
10
  ],
12
11
  "homepage": "https://github.com/yamavol/markdown-it-adv-table#readme",
13
12
  "bugs": {
@@ -20,34 +19,28 @@
20
19
  "license": "MIT",
21
20
  "author": "yamavol",
22
21
  "type": "module",
23
- "main": "dist/index.js",
24
- "types": "dist/index.d.ts",
25
- "directories": {
26
- "doc": "docs",
27
- "test": "test"
28
- },
22
+ "main": "lib/index.js",
23
+ "types": "lib/index.d.ts",
29
24
  "files": [
30
- "dist/**/*.js",
31
- "dist/**/*.d.ts"
25
+ "lib/**/*.js",
26
+ "lib/**/*.d.ts"
32
27
  ],
33
28
  "scripts": {
34
29
  "build": "tsc",
35
- "build:dist": "tsc --build tsconfig.dist.json",
30
+ "build:dev": "tsc --build tsconfig.dev.json",
36
31
  "test": "vitest",
37
32
  "coverage": "vitest run --coverage",
38
33
  "lint": "eslint src",
39
34
  "lint:fix": "eslint src --fix"
40
35
  },
41
36
  "devDependencies": {
42
- "@stylistic/eslint-plugin": "^4.2.0",
37
+ "@cobapen/eslint-config": "^0.4.0",
43
38
  "@types/markdown-it": "^14.1.2",
44
39
  "@types/node": "^22.14.1",
45
40
  "@vitest/coverage-v8": "^3.1.1",
46
41
  "eslint": "^9.24.0",
47
- "eslint-plugin-import": "^2.31.0",
48
42
  "markdown-it": "^14.1.0",
49
43
  "typescript": "^5.8.3",
50
- "typescript-eslint": "^8.29.1",
51
44
  "vitest": "^3.1.1"
52
45
  }
53
46
  }
package/dist/cell.d.ts DELETED
@@ -1,33 +0,0 @@
1
- type HAlign = "left" | "center" | "right";
2
- /**
3
- * A state machine to track cell position and its attributes
4
- */
5
- export declare class CellState {
6
- private static readonly _initialPos;
7
- private _pos;
8
- private _numCols;
9
- private _colsAttr;
10
- private _cells;
11
- constructor(columns: number);
12
- get numCols(): number;
13
- get pos(): [number, number];
14
- get row(): number;
15
- set row(num: number);
16
- get col(): number;
17
- set col(num: number);
18
- init(numCols: number): void;
19
- setColWidth(col: number, width?: string): void;
20
- setColAlign(col: number, align?: HAlign): void;
21
- setColSpan(row: number, col: number, cspan: number): void;
22
- setRowSpan(row: number, col: number, rspan: number): void;
23
- /**
24
- * Return the next available cell
25
- */
26
- next(): {
27
- row: number;
28
- col: number;
29
- };
30
- isUsed(row: number, col: number): boolean;
31
- private markUsed;
32
- }
33
- export {};
package/dist/cell.js DELETED
@@ -1,105 +0,0 @@
1
- /**
2
- * A state machine to track cell position and its attributes
3
- */
4
- export class CellState {
5
- static _initialPos = [-1, -1];
6
- _pos;
7
- _numCols;
8
- _colsAttr;
9
- _cells;
10
- constructor(columns) {
11
- this._numCols = Math.max(columns, 1);
12
- this._pos = [...CellState._initialPos];
13
- this._colsAttr = Array(this._numCols).fill({});
14
- this._cells = {};
15
- }
16
- get numCols() {
17
- return this._numCols;
18
- }
19
- get pos() {
20
- return this._pos;
21
- }
22
- get row() {
23
- return this._pos[0];
24
- }
25
- set row(num) {
26
- this._pos[0] = num;
27
- }
28
- get col() {
29
- return this._pos[1];
30
- }
31
- set col(num) {
32
- this._pos[1] = num;
33
- }
34
- init(numCols) {
35
- this._numCols = numCols;
36
- this._pos = [...CellState._initialPos];
37
- this._cells = {};
38
- }
39
- setColWidth(col, width) {
40
- this._colsAttr[col].width = width;
41
- }
42
- setColAlign(col, align) {
43
- this._colsAttr[col].align = align;
44
- }
45
- setColSpan(row, col, cspan) {
46
- const key = mapKey(row, col);
47
- this._cells[key].colspan = cspan;
48
- for (let c = col; c < col + cspan; c++) {
49
- const key = mapKey(row, c);
50
- const cell = this._cells[key];
51
- cell.assigned = true;
52
- }
53
- }
54
- setRowSpan(row, col, rspan) {
55
- const key = mapKey(row, col);
56
- this._cells[key].rowspan = rspan;
57
- for (let r = row; r < row + rspan; r++) {
58
- const key = mapKey(r, col);
59
- const cell = this._cells[key];
60
- cell.assigned = true;
61
- }
62
- }
63
- /**
64
- * Return the next available cell
65
- */
66
- next() {
67
- if (this.row === -1) {
68
- this.row = 0;
69
- this.col = 0;
70
- }
71
- else {
72
- // skip reserved cells for cspan/rspan, and return next valid cell. WIP
73
- while (this.isUsed(this.row, this.col)) {
74
- this.col++;
75
- if (this.col >= this._numCols) {
76
- this.col = 0;
77
- this.row++;
78
- }
79
- }
80
- }
81
- this.markUsed(this.row, this.col);
82
- return {
83
- row: this.row,
84
- col: this.col,
85
- };
86
- }
87
- isUsed(row, col) {
88
- const key = mapKey(row, col);
89
- return this._cells[key]?.assigned === true;
90
- }
91
- markUsed(row, col) {
92
- const key = mapKey(row, col);
93
- const map = this._cells[key];
94
- if (map === undefined) {
95
- this._cells[key] = { assigned: true };
96
- }
97
- else {
98
- map.assigned = true;
99
- }
100
- }
101
- }
102
- function mapKey(row, column) {
103
- return `${row}-${column}`;
104
- }
105
- //# sourceMappingURL=cell.js.map
package/dist/utils.d.ts DELETED
@@ -1,4 +0,0 @@
1
- export type DeepPartial<T> = {
2
- [P in keyof T]?: T[P] extends Array<infer U> ? Array<DeepPartial<U>> : T[P] extends object ? T[P] extends Function ? T[P] : DeepPartial<T[P]> : T[P];
3
- };
4
- export declare function deepmerge<T, U>(target: Partial<T>, source?: Partial<U>): T & U;
package/dist/utils.js DELETED
@@ -1,47 +0,0 @@
1
- function isPrimitive(value) {
2
- return (value === null
3
- || typeof value === "string"
4
- || typeof value === "number"
5
- || typeof value === "boolean"
6
- || typeof value === "symbol"
7
- || typeof value === "bigint"
8
- || typeof value === "undefined");
9
- }
10
- function isPlainObject(obj) {
11
- return Object.prototype.toString.call(obj) === "[object Object]"
12
- && Object.getPrototypeOf(obj) === Object.prototype;
13
- }
14
- export function deepmerge(target, source) {
15
- const seen = new WeakSet();
16
- function merge(target, source) {
17
- if (seen.has(source)) {
18
- return undefined;
19
- }
20
- if (isPrimitive(source)) {
21
- return source;
22
- }
23
- if (Array.isArray(source)) {
24
- seen.add(source);
25
- return source.map(item => merge(undefined, item));
26
- }
27
- if (isPlainObject(source)) {
28
- seen.add(source);
29
- const result = isPlainObject(target) ? { ...target } : {};
30
- for (const key of Object.keys(source)) {
31
- // Skip dangerous keys
32
- if (key === "__proto__" || key === "constructor" || key === "prototype") {
33
- continue;
34
- }
35
- const value = source[key];
36
- const merged = merge(result[key], value);
37
- if (merged !== undefined) {
38
- result[key] = merged;
39
- }
40
- }
41
- return result;
42
- }
43
- return undefined;
44
- }
45
- return merge(target, source);
46
- }
47
- //# sourceMappingURL=utils.js.map
File without changes
File without changes
File without changes
File without changes