1 | import { getPeopleHTML } from './util.js'
|
2 | import spdxParse from 'spdx-expression-parse'
|
3 | import spdxList from 'spdx-license-list/full'
|
4 | import type Fellow from 'fellow'
|
5 |
|
6 | function renderSpdxObject(
|
7 | spdxObject: any,
|
8 | output: 'description' | 'body',
|
9 | depth: number = 0
|
10 | ): string {
|
11 | if (spdxObject.license) {
|
12 | const code = spdxObject.license
|
13 | const details = spdxList[code]
|
14 |
|
15 | if (!details) {
|
16 | throw new Error(`Could not find the details for the license ${code}`)
|
17 | }
|
18 |
|
19 | const name = details.name
|
20 | const body = details.licenseText
|
21 | const url = `http://spdx.org/licenses/${code}.html`
|
22 |
|
23 | return output === 'description'
|
24 | ? depth === 0
|
25 | ? `<ul><li><a href="${url}">${name}</a></li></ul>`
|
26 | : `<a href="${url}">${name}</a>`
|
27 | : body
|
28 |
|
29 | .replace('\nCopyright (c) <year> <copyright holders>\n', '')
|
30 |
|
31 | .replace(/\s?Copyright.+holders>/gi, '')
|
32 |
|
33 | .replace(/^[\s\S]+<<endOptional>>\s*/m, '')
|
34 |
|
35 |
|
36 | .replace(
|
37 | /^(.+?)\n\s*([\s\S]+)\s*$/,
|
38 | '<h2>$1</h2>\n\n<pre>\n$2\n</pre>'
|
39 | )
|
40 | } else if (spdxObject.conjunction) {
|
41 | const left = renderSpdxObject(spdxObject.left, output, depth + 1)
|
42 | const middle = spdxObject.conjunction
|
43 | const right = renderSpdxObject(spdxObject.right, output, depth + 1)
|
44 | return output === 'description'
|
45 | ? `<ul><li>${left}</li>\n<li>${middle}</li>\n<li>${right}</li></ul>`
|
46 | : `${left}\n\n${right}\n\n`.trim()
|
47 | } else {
|
48 | throw new Error(
|
49 | `Unknown spdx object value: ${JSON.stringify(spdxObject, null, ' ')}`
|
50 | )
|
51 | }
|
52 | }
|
53 |
|
54 | function getLicensesHTML(
|
55 | spdxString: string,
|
56 | output: 'description' | 'body'
|
57 | ): string {
|
58 | const sdpxObject = spdxParse(spdxString)
|
59 | return renderSpdxObject(sdpxObject, output)
|
60 | }
|
61 |
|
62 | function getLicenseIntroduction(data: {
|
63 | license: string
|
64 | authors: Fellow[]
|
65 | }): string {
|
66 |
|
67 | if (!data.license) {
|
68 | throw new Error('License file was requested, but no license was specified')
|
69 | }
|
70 |
|
71 |
|
72 | const result = [
|
73 | 'Unless stated otherwise all works are:',
|
74 | '',
|
75 | getPeopleHTML(data.authors, { displayCopyright: true, displayYears: true }),
|
76 | '',
|
77 | 'and licensed under:',
|
78 | '',
|
79 | getLicensesHTML(data.license, 'description'),
|
80 | ].join('\n')
|
81 |
|
82 |
|
83 | return result
|
84 | }
|
85 |
|
86 | interface LicenseOptions {
|
87 | license?: string
|
88 | authors: Fellow[]
|
89 | }
|
90 |
|
91 | interface LicenseConfig extends LicenseOptions {
|
92 | license: string
|
93 | }
|
94 |
|
95 | export function getLicenseFile(data: LicenseOptions): string {
|
96 |
|
97 | if (!data.license) {
|
98 | throw new Error('License file was requested, but no license was specified')
|
99 | }
|
100 |
|
101 |
|
102 | const result = [
|
103 | '<h1>License</h1>',
|
104 | '',
|
105 | getLicenseIntroduction(data as LicenseConfig),
|
106 | '',
|
107 | getLicensesHTML(data.license, 'body'),
|
108 | ].join('\n')
|
109 |
|
110 |
|
111 | return result
|
112 | }
|
113 |
|
114 | export function getLicenseSection(data: LicenseOptions): string {
|
115 |
|
116 | if (!data.license) {
|
117 | throw new Error('License file was requested, but no license was specified')
|
118 | }
|
119 |
|
120 |
|
121 | const result = [
|
122 | '<h2>License</h2>',
|
123 | '',
|
124 | getLicenseIntroduction(data as LicenseConfig),
|
125 | ].join('\n')
|
126 |
|
127 |
|
128 | return result
|
129 | }
|