puml-for-markdown 1.0.0 → 1.1.0
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.
- package/README.md +11 -0
- package/bin/index.js +7 -9
- package/index.js +27 -28
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -106,3 +106,14 @@ there are no issues using them in private repositories.
|
|
|
106
106
|
### Testing
|
|
107
107
|
Currently there is no TDD, for now I've just been using the example diagrams to test. The examples are pretty extensive
|
|
108
108
|
though.
|
|
109
|
+
|
|
110
|
+
### Other Helpful Links
|
|
111
|
+
* [C4-Puml](https://github.com/plantuml-stdlib/C4-PlantUML): A collection of PlantUML diagrams for use in C4, you'll see me using this in my examples
|
|
112
|
+
|
|
113
|
+
### More Examples
|
|
114
|
+
[](https://tinyurl.com/ya6qvr7r)<!---->
|
|
115
|
+
[](https://tinyurl.com/yblre3m4)<!---->
|
|
116
|
+
[](https://tinyurl.com/y8egw3wt)<!---->
|
|
117
|
+
[](https://tinyurl.com/y9j7twkz)<!---->
|
|
118
|
+
[](https://tinyurl.com/ybp8ju9x)<!---->
|
|
119
|
+
[](https://tinyurl.com/ya3cqxkv)<!---->
|
package/bin/index.js
CHANGED
|
@@ -38,13 +38,12 @@ new Command()
|
|
|
38
38
|
).default(false, 'rootDirectory')
|
|
39
39
|
)
|
|
40
40
|
.option(
|
|
41
|
-
'-g, --
|
|
42
|
-
'
|
|
43
|
-
true,
|
|
41
|
+
'-g, --ignore-gitignore',
|
|
42
|
+
"Don't ignore files PUML and MD files in projects gitignore",
|
|
44
43
|
)
|
|
45
44
|
.addOption(new Option(
|
|
46
45
|
'-i, --gitignore-path <path>',
|
|
47
|
-
'
|
|
46
|
+
'Use this as path to .gitignore file.'
|
|
48
47
|
).default(false, 'rootDirectory/.gitignore')
|
|
49
48
|
)
|
|
50
49
|
.option(
|
|
@@ -70,11 +69,10 @@ new Command()
|
|
|
70
69
|
opts.gitignorePath = opts.gitignorePath || path.resolve(opts.rootDirectory, '.gitignore')
|
|
71
70
|
opts.markdownDirectory = opts.markdownDirectory || opts.rootDirectory
|
|
72
71
|
opts.pumlDirectory = opts.pumlDirectory || opts.rootDirectory
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
}
|
|
72
|
+
opts.shouldShortenLinks = !opts.turnOffLinkShortening
|
|
73
|
+
opts.respectGitignore = !opts.ignoreGitignore
|
|
74
|
+
opts.imageFormats = opts.imageFormats === 'both' ? ['png', 'svg'] : [opts.imageFormats]
|
|
75
|
+
|
|
78
76
|
return run(opts).catch((e) => {
|
|
79
77
|
console.error('FATAL EXCEPTION')
|
|
80
78
|
console.error(e)
|
package/index.js
CHANGED
|
@@ -19,13 +19,15 @@ const parseGitIgnore = require('gitignore-globs');
|
|
|
19
19
|
|
|
20
20
|
// CONSTANTS
|
|
21
21
|
|
|
22
|
-
const
|
|
23
|
-
const PUML_PNG_SERVER = 'https://www.plantuml.com/plantuml/png'
|
|
22
|
+
const PUML_SERVER = 'https://www.plantuml.com/plantuml'
|
|
24
23
|
|
|
25
24
|
// HELPERS
|
|
26
25
|
|
|
27
26
|
const getBuffer = bent('buffer')
|
|
28
27
|
const mkdirIfDoesntExist = (p) => !fs.existsSync(p) && fs.mkdirSync(p, {recursive: true})
|
|
28
|
+
const getPumlUrl = (imgFormat, encodedData, shorten) => shorten ?
|
|
29
|
+
tiny.shorten(getFullPumlUrl(imgFormat, encodedData)) : getFullPumlUrl(imgFormat, encodedData)
|
|
30
|
+
const getFullPumlUrl = (imgFormat, encodedData) => `${PUML_SERVER}/${imgFormat}/${encodedData}}`
|
|
29
31
|
const mapUniqMatches = (s, re, mapper, match = re.exec(s), results = []) => {
|
|
30
32
|
if (match) return mapUniqMatches(s, re, mapper, re.exec(s), results.concat([match]))
|
|
31
33
|
return _.uniqBy(results, String).map(mapper)
|
|
@@ -53,23 +55,12 @@ const replaceMdIgnoringCode = (mdString, replaceFn) => {
|
|
|
53
55
|
return replaceMdIgnoringCodeBlocks(mdString, str => replaceMdIgnoringInlineCode(str, replaceFn))
|
|
54
56
|
}
|
|
55
57
|
|
|
56
|
-
const getPngUrl = encodedData => `${PUML_PNG_SERVER}/${encodedData}}`
|
|
57
|
-
const getSvgUrl = encodedData => `${PUML_SVG_SERVER}/${encodedData}}`
|
|
58
|
-
const getPumlTinyUrl = encodedData => tiny.shorten(getSvgUrl(encodedData))
|
|
59
|
-
const getImgUrl = (imageFormat, encodedData) => {
|
|
60
|
-
const imgFormatToGetUrlFn = {
|
|
61
|
-
png: getPngUrl,
|
|
62
|
-
svg: getSvgUrl
|
|
63
|
-
}
|
|
64
|
-
return imgFormatToGetUrlFn[imageFormat](encodedData)
|
|
65
|
-
}
|
|
66
|
-
|
|
67
58
|
// DATA STRUCTURES
|
|
68
59
|
|
|
69
60
|
class PumlLinks extends Map {
|
|
70
|
-
constructor(pumlPaths,
|
|
61
|
+
constructor(pumlPaths, shouldShortenLinks) {
|
|
71
62
|
super();
|
|
72
|
-
this.
|
|
63
|
+
this.shouldShortenLinks = shouldShortenLinks
|
|
73
64
|
// Mark paths so we know which should be visited
|
|
74
65
|
// Any path that's not marked 0 we know isn't a puml path because it doesn't correspond to a puml fil
|
|
75
66
|
pumlPaths.forEach(p => this.set(p, 0))
|
|
@@ -83,7 +74,7 @@ class PumlLinks extends Map {
|
|
|
83
74
|
if (typeof v === 'number') return super.set(pumlPath, v)
|
|
84
75
|
|
|
85
76
|
const encodedData = plantUmlEncoder.encode(v)
|
|
86
|
-
const url =
|
|
77
|
+
const url = await getPumlUrl('svg', encodedData, this.shouldShortenLinks)
|
|
87
78
|
return super.set(pumlPath, {encodedData, url, data: v});
|
|
88
79
|
}
|
|
89
80
|
|
|
@@ -99,13 +90,13 @@ const downloadImg = async (outputPath, imgUrl) => {
|
|
|
99
90
|
fs.writeFileSync(outputPath, imgBuffer)
|
|
100
91
|
}
|
|
101
92
|
|
|
102
|
-
const saveDiagram = async ({rootDirectory, distDirectory, pumlPath,
|
|
93
|
+
const saveDiagram = async ({rootDirectory, distDirectory, pumlPath, imgFormat, encodedData}) => {
|
|
103
94
|
const outputPath = path.join(
|
|
104
|
-
distDirectory, pumlPath.replace(rootDirectory, '').replace(/\.puml$/, `.${
|
|
95
|
+
distDirectory, pumlPath.replace(rootDirectory, '').replace(/\.puml$/, `.${imgFormat}`)
|
|
105
96
|
)
|
|
106
97
|
|
|
107
98
|
mkdirIfDoesntExist(path.dirname(outputPath))
|
|
108
|
-
const imgUrl =
|
|
99
|
+
const imgUrl = getFullPumlUrl(imgFormat, encodedData)
|
|
109
100
|
try {
|
|
110
101
|
await downloadImg(outputPath, imgUrl)
|
|
111
102
|
} catch (e) {
|
|
@@ -117,9 +108,9 @@ const saveDiagram = async ({rootDirectory, distDirectory, pumlPath, imageFormat,
|
|
|
117
108
|
const saveDiagrams = async ({ rootDirectory, distDirectory, imageFormats, pumlLinks }) => {
|
|
118
109
|
fs.rmSync(distDirectory, {recursive: true, force: true});
|
|
119
110
|
for (let [pumlPath, {encodedData}] of pumlLinks) {
|
|
120
|
-
for (let
|
|
111
|
+
for (let imgFormat of imageFormats) {
|
|
121
112
|
await saveDiagram({
|
|
122
|
-
distDirectory, rootDirectory, pumlPath,
|
|
113
|
+
distDirectory, rootDirectory, pumlPath, imgFormat, encodedData
|
|
123
114
|
})
|
|
124
115
|
}
|
|
125
116
|
}
|
|
@@ -151,6 +142,7 @@ const processPumlFile = async (pumlPath, pumlLinks) => {
|
|
|
151
142
|
|
|
152
143
|
let data = fs.readFileSync(pumlPath, 'utf8')
|
|
153
144
|
await Promise.all(mapUniqMatches(data, /\$link=["']([^"']+)['"]/gm, async ([pumlLink, pumlLinkPath]) => {
|
|
145
|
+
// console.debug(pumlLink, pumlLinkPath)
|
|
154
146
|
const newLink = await processPumlFile(path.resolve(path.dirname(pumlPath), pumlLinkPath), pumlLinks)
|
|
155
147
|
data = data.replaceAll(pumlLink, `$link="${newLink.url}"`)
|
|
156
148
|
}))
|
|
@@ -168,7 +160,7 @@ const processMdFile = async (mdPath, pumlLinks) => {
|
|
|
168
160
|
console.info(`Processing md file at ${mdPath}`)
|
|
169
161
|
let originalMdStr = fs.readFileSync(mdPath, 'utf8')
|
|
170
162
|
const findMdPumlLinksRE = new RegExp(
|
|
171
|
-
`(\\[
|
|
163
|
+
`(\\[.*\]\\([^)]+\\))?<!\-\-(!?\\[[^\\]]+\\])\\(([^)]+\\.puml)\\)\-\->`, 'g'
|
|
172
164
|
)
|
|
173
165
|
// Add puml server tinyurl link for puml links indicated in markdown comments
|
|
174
166
|
const mdWithUpdatedPumlLinks = replaceMdIgnoringCode(originalMdStr, (str) => {
|
|
@@ -178,12 +170,17 @@ const processMdFile = async (mdPath, pumlLinks) => {
|
|
|
178
170
|
if (!pumlLink) {
|
|
179
171
|
throw Error(`Could not find puml for md link path = ${mdPumlLinkPath}, absolute path = ${pumlPath}`)
|
|
180
172
|
}
|
|
173
|
+
let replacement
|
|
181
174
|
// If the puml link is a markdown image
|
|
182
175
|
if (linkText[0] === '!') {
|
|
183
|
-
|
|
176
|
+
replacement = `[${linkText}(${pumlLink.url})](${pumlLink.url})<!--${linkText}(${mdPumlLinkPath})-->`
|
|
177
|
+
} else {
|
|
178
|
+
// If the puml link is a markdown hyperlink
|
|
179
|
+
replacement = `${linkText}(${pumlLink.url})<!--${linkText}(${mdPumlLinkPath})-->`
|
|
184
180
|
}
|
|
185
|
-
|
|
186
|
-
|
|
181
|
+
|
|
182
|
+
// console.debug({match, linkText, mdPumlLinkPath, replacement})
|
|
183
|
+
return replacement
|
|
187
184
|
})
|
|
188
185
|
})
|
|
189
186
|
|
|
@@ -201,7 +198,7 @@ const runOnce = async (
|
|
|
201
198
|
imageFormats,
|
|
202
199
|
respectGitignore,
|
|
203
200
|
gitignorePath,
|
|
204
|
-
|
|
201
|
+
shouldShortenLinks,
|
|
205
202
|
}
|
|
206
203
|
) => {
|
|
207
204
|
assert(fs.existsSync(markdownDirectory), "That's an invalid md folder path")
|
|
@@ -210,13 +207,15 @@ const runOnce = async (
|
|
|
210
207
|
const ignore = respectGitignore ? parseGitIgnore(gitignorePath) : []
|
|
211
208
|
const mdPaths = glob.sync(`${markdownDirectory}/**/*.md`, {ignore, nodir: true})
|
|
212
209
|
const pumlPaths = glob.sync(`${pumlDirectory}/**/*.puml`, {ignore, nodir: true})
|
|
213
|
-
const pumlLinks = new PumlLinks(pumlPaths,
|
|
210
|
+
const pumlLinks = new PumlLinks(pumlPaths, shouldShortenLinks)
|
|
214
211
|
|
|
215
212
|
for (let p of pumlPaths) await processPumlFile(p, pumlLinks)
|
|
216
213
|
for (let p of mdPaths) await processMdFile(p, pumlLinks)
|
|
217
214
|
|
|
218
215
|
if (outputImages) {
|
|
219
|
-
await saveDiagrams({
|
|
216
|
+
await saveDiagrams({
|
|
217
|
+
rootDirectory, distDirectory, imageFormats, pumlLinks
|
|
218
|
+
})
|
|
220
219
|
}
|
|
221
220
|
}
|
|
222
221
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "puml-for-markdown",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "An application to add interactive PUML diagrams to your github markdown files. If running with default arguments, run in project root directory.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|