Skip to content

Commit

Permalink
Allow HTML tags to be parsable
Browse files Browse the repository at this point in the history
  • Loading branch information
PaulioRandall committed May 1, 2024
1 parent fc70bf6 commit 31e09e4
Show file tree
Hide file tree
Showing 5 changed files with 174 additions and 17 deletions.
4 changes: 2 additions & 2 deletions package-lock.json

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

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"description": "Simple tool for adding parsable metadata as comments within Svelte components.",
"type": "module",
"license": "MIT",
"version": "0.3.0",
"version": "0.4.0",
"engines": {
"node": ">=18"
},
Expand Down
47 changes: 44 additions & 3 deletions src/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,17 @@ const defaultGlobOptions = {
nodir: true,
}

export const newNodeRegExp = (prefix = 'p23') => {
export const newJavaScriptNodeRegexp = (prefix = 'p23') => {
return RegExp(
`^[^S\r\n]*//${prefix}((?:.[$a-zA-Z_][$a-zA-Z_0-9]*)+):(.*)$`,
'mgi'
'igm'
)
}

export const newHtmlNodeRegexp = (prefix = 'p23') => {
return RegExp(
`^[^S\r\n]*<!--${prefix}((?:.[$a-zA-Z_][$a-zA-Z_0-9]*)+):(.*?)-->`,
'igms'
)
}

Expand Down Expand Up @@ -64,9 +71,25 @@ const extractNodes = (data, options) => {
// Examples:
//p23.name: Abc
//p23.group.name: Abc
const jsRegexp = newJavaScriptNodeRegexp(options.prefix)
const jsNodes = extractNodesWithRegexp(data, jsRegexp)

// Examples:
//<!--p23.name: Abc-->
//<!--p23.group.name: Abc-->
//<!--p23.group.name:
// Abc
//-->
const htmlRegexp = newHtmlNodeRegexp(options.prefix)
const htmlNodes = extractNodesWithRegexp(data, htmlRegexp)

const n = joinNodeTrees(jsNodes, htmlNodes)
console.log(n)
return n
}

const extractNodesWithRegexp = (data, regexp) => {
const nodes = {}
const regexp = newNodeRegExp(options.prefix)
let next = null

while ((next = regexp.exec(data)) !== null) {
Expand All @@ -80,6 +103,24 @@ const extractNodes = (data, options) => {
return nodes
}

const joinNodeTrees = (a, b) => {
if (typeof a !== 'object') {
return structuredClone(b)
}

const nodes = structuredClone(a)

for (const name in b) {
if (typeof b[name] === 'object') {
nodes[name] = joinNodeTrees(nodes[name], b[name])
} else {
nodes[name] = b[name]
}
}

return nodes
}

const parseNodeNames = (nodeNames) => {
return nodeNames.split('.').filter((s) => !!s)
}
Expand Down
121 changes: 110 additions & 11 deletions src/parser.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import upath from 'upath'
import { parse, newNodeRegExp } from './parser.js'
import { parse, newJavaScriptNodeRegexp, newHtmlNodeRegexp } from './parser.js'

const testdataDir = './src/testdata'

Expand All @@ -24,15 +24,15 @@ const parseToUnix = (f) => {
}

describe('p23', () => {
describe('newNodeRegExp', () => {
describe('newJavaScriptNodeRegexp', () => {
test('Non-nested node', () => {
const act = newNodeRegExp().exec('//p23.name:value')
const act = newJavaScriptNodeRegexp().exec('//p23.name:value')
const exp = expect.arrayContaining(['//p23.name:value', '.name', 'value'])
expect(act).toEqual(exp)
})

test('Custom prefix', () => {
const act = newNodeRegExp('my_custom_prefix').exec(
const act = newJavaScriptNodeRegexp('my_custom_prefix').exec(
'//my_custom_prefix.name:value'
)
const exp = expect.arrayContaining([
Expand All @@ -44,7 +44,7 @@ describe('p23', () => {
})

test('Nested node', () => {
const act = newNodeRegExp().exec('//p23.group.name:value')
const act = newJavaScriptNodeRegexp().exec('//p23.group.name:value')
const exp = expect.arrayContaining([
'//p23.group.name:value',
'.group.name',
Expand All @@ -54,7 +54,7 @@ describe('p23', () => {
})

test('Messed up but valid node names', () => {
const act = newNodeRegExp().exec(
const act = newJavaScriptNodeRegexp().exec(
'//p23.$$$12313___.__dsfjk12$$6389__$$:value'
)
const exp = expect.arrayContaining([
Expand All @@ -66,28 +66,100 @@ describe('p23', () => {
})

test('Empty value still returns entry', () => {
const act = newNodeRegExp().exec('//p23.name:')
const act = newJavaScriptNodeRegexp().exec('//p23.name:')
const exp = expect.arrayContaining(['//p23.name:', '.name', ''])
expect(act).toEqual(exp)
})

test('Fails if number first in node name', () => {
const act = newNodeRegExp().exec('//p23.1name:value')
const act = newJavaScriptNodeRegexp().exec('//p23.1name:value')
expect(act).toEqual(null)
})

test('Fails if missing node name', () => {
const act = newNodeRegExp().exec('//p23:value')
const act = newJavaScriptNodeRegexp().exec('//p23:value')
expect(act).toEqual(null)
})

test('Fails if missing node name (version two)', () => {
const act = newNodeRegExp().exec('//p23.:value')
const act = newJavaScriptNodeRegexp().exec('//p23.:value')
expect(act).toEqual(null)
})

test('Fails if missing colon', () => {
const act = newNodeRegExp().exec('//p23.name')
const act = newJavaScriptNodeRegexp().exec('//p23.name')
expect(act).toEqual(null)
})
})

describe('newHtmlNodeRegexp', () => {
test('Non-nested node', () => {
const act = newHtmlNodeRegexp().exec('<!--p23.name:value-->')
const exp = expect.arrayContaining([
'<!--p23.name:value-->',
'.name',
'value',
])
expect(act).toEqual(exp)
})

test('Custom prefix', () => {
const act = newHtmlNodeRegexp('my_custom_prefix').exec(
'<!--my_custom_prefix.name:value-->'
)
const exp = expect.arrayContaining([
'<!--my_custom_prefix.name:value-->',
'.name',
'value',
])
expect(act).toEqual(exp)
})

test('Nested node', () => {
const act = newHtmlNodeRegexp().exec('<!--p23.group.name:value-->')
const exp = expect.arrayContaining([
'<!--p23.group.name:value-->',
'.group.name',
'value',
])
expect(act).toEqual(exp)
})

test('Messed up but valid node names', () => {
const act = newHtmlNodeRegexp().exec(
'<!--p23.$$$12313___.__dsfjk12$$6389__$$:value-->'
)
const exp = expect.arrayContaining([
'<!--p23.$$$12313___.__dsfjk12$$6389__$$:value-->',
'.$$$12313___.__dsfjk12$$6389__$$',
'value',
])
expect(act).toEqual(exp)
})

test('Empty value still returns entry', () => {
const act = newHtmlNodeRegexp().exec('<!--p23.name:-->')
const exp = expect.arrayContaining(['<!--p23.name:-->', '.name', ''])
expect(act).toEqual(exp)
})

test('Fails if number first in node name', () => {
const act = newHtmlNodeRegexp().exec('<!--p23.1name:value-->')
expect(act).toEqual(null)
})

test('Fails if missing node name', () => {
const act = newHtmlNodeRegexp().exec('<!--p23:value-->')
expect(act).toEqual(null)
})

test('Fails if missing node name (version two)', () => {
const act = newHtmlNodeRegexp().exec('<!--p23.:value-->')
expect(act).toEqual(null)
})

test('Fails if missing colon', () => {
const act = newHtmlNodeRegexp().exec('<!--p23.name-->')
expect(act).toEqual(null)
})
})
Expand Down Expand Up @@ -232,5 +304,32 @@ describe('p23', () => {
},
])
})

test('Parses with HTML docs', () => {
const file = createSvelteFilePath('htmlDocs')
const metadata = parse(file)

expect(metadata).toEqual([
{
...generateFileFields(file),
nodes: {
type: 'Music',
music: {
type: 'Band',
band: {
name: 'Rhapsody of Fire',
genre: 'Symphonic Power Metal',
albums: `
[
"Rhapsody of Fire",
"Triumph or Agony",
]
`,
},
},
},
},
])
})
})
})
17 changes: 17 additions & 0 deletions src/testdata/files/htmlDocs.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<script>
//p23.type:Music
//p23.music.type:Band
</script>

<!--p23.music.band.genre:Symphonic Power Metal-->

<div>
<!--p23.music.band.name:Rhapsody of Fire-->
</div>

<!--p23.music.band.albums:
[
"Rhapsody of Fire",
"Triumph or Agony",
]
-->

0 comments on commit 31e09e4

Please sign in to comment.