forked from npm/documentation
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtransform.js
More file actions
144 lines (124 loc) · 4.02 KB
/
transform.js
File metadata and controls
144 lines (124 loc) · 4.02 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
const parseFm = require('front-matter')
const Minipass = require('minipass')
const yaml = require('yaml')
const minimatch = require('minimatch')
const { sep, join, posix, isAbsolute } = require('path')
const gh = require('./gh')
const rawRedirects = require('./redirects')
const getPathParts = (path) => {
const abs = isAbsolute(path)
const paths = path.replace(/\.mdx?$/, '').split(sep)
const pathId = posix.join(abs ? '/' : '', ...paths)
const page = posix.basename(pathId)
const section = posix.dirname(pathId)
return {
path: pathId,
page,
section: section === '.' ? '' : section,
}
}
const getRedirects = ({ path, release }) => {
const redirects = [getPathParts(path)]
const [pagePath] = redirects
const canonical = posix.join(
release.url,
pagePath.section,
pagePath.page === 'index' ? '' : pagePath.page
)
for (const [k, v] of Object.entries(rawRedirects).reverse()) {
const pageRedirects = redirects.flatMap(redirect => {
if (minimatch(redirect.path, k)) {
return v({ ...getPathParts(redirect.path), release }).map(p => ({
...redirect,
...typeof p === 'object' ? p : { path: p },
}))
}
})
redirects.push(...pageRedirects.filter(Boolean))
}
const prefixRedirects = redirects
.flatMap(redirect => {
const useDefault = redirect.default || release.default
if (isAbsolute(redirect.path)) {
return useDefault ? redirect.path : null
} else {
return release.urlPrefixes.flatMap(p => [
posix.join('/', p, release.id, redirect.path),
useDefault ? posix.join('/', p, redirect.path) : null,
])
}
})
.filter(Boolean)
.filter(r => r !== canonical)
return [...new Set(prefixRedirects)]
.sort((a, b) => a.localeCompare(b, 'en'))
}
const transform = (data, { release, path, frontmatter }) => {
let { attributes, body } = parseFm(data.toString())
/* istanbul ignore next */
if (!attributes.redirect_from) {
attributes.redirect_from = []
}
attributes.redirect_from.push(...getRedirects({ path, release }))
const ghFrontmatter = {
github_repo: gh.nwo,
github_branch: release.branch,
github_path: join(release.src, path).split(sep).join(posix.sep),
}
const order = [
'title',
'shortName',
'section',
'description',
'github_repo',
'github_branch',
'github_path',
'redirect_from',
]
const sortRedirects = (a, b) => a.localeCompare(b, 'en')
attributes = Object.fromEntries(
Object.entries({ ...attributes, ...ghFrontmatter, ...frontmatter })
.filter(([, v]) => (Array.isArray(v) ? v.length : true))
.map(([k, v]) => (Array.isArray(v) ? [k, v.sort(sortRedirects)] : [k, v]))
.sort(([a], [b]) => {
/* istanbul ignore next */
const aIndex = order.includes(a) ? order.indexOf(a) : order.length
/* istanbul ignore next */
const bIndex = order.includes(b) ? order.indexOf(b) : order.length
return aIndex - bIndex
})
)
body = body
// some legacy versions of the docs did not get this replaced
// in the source so we need to replace it here
.replace(/@VERSION@/g, release.version)
// also replace all internal markdown links with links to this
// specific version
.replace(
/\[([^\]]+)\]\(\/((?:commands|configuring-npm|using-npm)\/[^)]+)\)/g,
(_, p1, p2) => `[${p1}](${release.url}/${p2})`
)
return `---\n${yaml.stringify(attributes).trim()}\n---\n\n${body}`
}
// copied from minipass-collect. collects all chunks into a single
// buffer which is then transformed before a final write event
class Transform extends Minipass {
#data = []
#length = 0
#opts = {}
constructor (transformOpts) {
super({ encoding: 'utf-8' })
this.#opts = transformOpts
}
write (c) {
this.#data.push(c)
this.#length += c.length
return true
}
end () {
super.write(transform(Buffer.concat(this.#data, this.#length), this.#opts))
return super.end()
}
}
module.exports = Transform
module.exports.sync = transform