Skip to content

Commit 0432ea7

Browse files
committed
fix: handle wmic mixed formatting
1 parent de7bc03 commit 0432ea7

File tree

4 files changed

+338
-43
lines changed

4 files changed

+338
-43
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { parse } from '@webpod/ingrid'
99

1010
const table = `
1111
foo bar baz
12-
1 2 3
12+
1 2 3
1313
`
1414
const result = parse(table.trim())
1515
// {foo: ['1'], bar: ['2'], baz: ['3']}
@@ -36,7 +36,7 @@ const result = parse(table.trim(), {format: 'win'})
3636
[
3737
{ foo: ['1'], bar: ['2'], baz: ['3'] },
3838
{ foo: ['a'], bar: ['b'], baz: ['c'] },
39-
{ foo: ['a'], bar: ['d'], baz: ['e'] }
39+
{ foo: ['d'], bar: ['e'], baz: ['-'] }
4040
]
4141
*/
4242
```

src/main/ts/ingrid.ts

Lines changed: 62 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export type TIngridParseOpts = Partial<{
77
export type TIngridParse = (input: string) => TIngridResponse
88

99
const EOL = /\r?\n|\r|\n/
10+
const EMPTY = '-'
1011

1112
type TLineDigest = {
1213
spaces: number[],
@@ -61,7 +62,7 @@ export const parseLine = (line: string, sep = ' '): TLineDigest => {
6162
}
6263

6364
export const parseLines = (input: string, sep?: string): TLineDigest[] =>
64-
input.split(EOL).map(l => parseLine(l, sep))
65+
input.split(EOL).filter(Boolean).map(l => parseLine(l, sep))
6566

6667
const countWordsByIndex = ({words}: TLineDigest, index: number): number => words.filter(({e}) => e < index).length
6768

@@ -126,45 +127,74 @@ const gridToData = (grid: string[][][]): TIngridResponse => {
126127
return data
127128
}
128129

129-
const cut = (line: string, points: number[], pad = 2): string[] => {
130-
const chunks: string[] = []
131-
let s = 0
132-
for (const i in [...points, Number.POSITIVE_INFINITY]) {
133-
const chunk = line.slice(s, points[i])
134-
chunks.push(chunk)
135-
s = points[i] + pad
130+
// eslint-disable-next-line sonarjs/cognitive-complexity
131+
export const parseWinGrid = (input: string): TIngridResponse => {
132+
const _lines = input.split(/\r?\n/)
133+
const lines = _lines.filter(Boolean)
134+
const headline = lines.shift()!
135+
const headers = headline.split(/\s+/)
136+
const ll = lines[0].length
137+
const hl = headers.length
138+
139+
if (lines.every(l => l.length === ll)) {
140+
const spaces = Array
141+
.from({ length: ll })
142+
.map((_, i) =>
143+
lines.every(l => l[i] === ' ')
144+
)
145+
const borders = spaces
146+
.reduce<number[]>((m, v, i, a) => {
147+
if ( v && !a[i - 1]) m.push(i)
148+
return m
149+
}, [0])
150+
const data: TIngridResponse = []
151+
152+
for (const line of lines) {
153+
const props: [string, [string]][] = []
154+
for (const i in headers) {
155+
const k = headers[i]
156+
const s = borders[i]
157+
const e = borders[+i + 1] || ll
158+
const v = line.slice(s, e).trim()
159+
props.push([k, [v || EMPTY]])
160+
}
161+
data.push(Object.fromEntries(props))
162+
}
163+
return data
136164
}
137165

138-
return chunks
139-
}
140-
141-
export const parseWinGrid = (input: string): TIngridResponse => {
142-
const lines = input.split(EOL)
143-
const headers = lines[0].trim().split(/\s+/)
166+
let w = ''
167+
let p
168+
const body = input.slice(headline.length)
169+
const vals: string[] = []
144170
const data: TIngridResponse = []
145171

146-
let memo = null
147-
for (const line of lines.slice(1)) {
148-
if (!line) continue
172+
const cap = (v?: string) => {
173+
const _v = w.trim() || (vals.length === 0 ? v : w.trim())
174+
if (!_v) return
149175

150-
const {spaces} = parseLine(line)
151-
const borders = spaces.filter((s, i) => spaces[i + 1] === s + 1 && spaces[i + 2] !== s + 2)
152-
153-
let chunks = (borders.length > 0 ? cut(line, borders, 2) : [line]).map(l => l.trim())//.filter(Boolean)
154-
if (chunks.length < headers.length) {
155-
memo = chunks
156-
continue
157-
} else if (chunks[0]?.trim()) {
158-
memo = null
159-
} else {
160-
chunks = [...(memo || ['<unknown>']), ...chunks].filter(Boolean)
176+
vals.push(_v)
177+
if (vals.length === hl) {
178+
data.push(Object.fromEntries(headers.map((h, i) => [h, [vals[i]]])))
179+
vals.length = 0
161180
}
181+
w = ''
182+
}
162183

163-
const entry: TIngridResponse[number] = Object.fromEntries(headers.map((header, i) =>
164-
[header, parseLine(chunks[i] || '').words.map(({w}) => w)]
165-
))
166-
data.push(entry)
184+
for (const c of body) {
185+
w += c
186+
if (c === ' ') {
187+
if (p === '\n') {
188+
cap(EMPTY)
189+
} else if (p === ' ') {
190+
cap()
191+
}
192+
} else if (c === '\n') {
193+
cap()
194+
}
195+
p = c
167196
}
197+
cap()
168198

169199
return data
170200
}

0 commit comments

Comments
 (0)