-
-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
110 additions
and
181 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,184 +1,131 @@ | ||
import fs from 'fs' | ||
import {promises as fs} from 'fs' | ||
import path from 'path' | ||
import parse from 'parse-author' | ||
import spdx from 'spdx-license-list' | ||
import {read} from 'to-vfile' | ||
import {findUpOne} from 'vfile-find-up' | ||
import {headingRange} from 'mdast-util-heading-range' | ||
|
||
var licenseRegexp = /^licen[cs]e(?=$|\.)/i | ||
var licenseHeadingRegexp = /^licen[cs]e$/i | ||
var http = 'http://' | ||
var https = 'https://' | ||
const licenseRegexp = /^licen[cs]e(?=$|\.)/i | ||
const licenseHeadingRegexp = /^licen[cs]e$/i | ||
const http = 'http://' | ||
const https = 'https://' | ||
|
||
/* Add a license section. */ | ||
export default function remarkLicense(options) { | ||
var settings = options || {} | ||
var finals = settings.ignoreFinalDefinitions | ||
var test = settings.heading || licenseHeadingRegexp | ||
|
||
var headingOptions = { | ||
ignoreFinalDefinitions: | ||
finals === undefined || finals === null ? true : finals, | ||
test: test | ||
} | ||
|
||
return transformer | ||
|
||
function transformer(tree, file, next) { | ||
var cwd = file.cwd | ||
var left = 2 // Two async operations. | ||
var defaultName | ||
var defaultUrl | ||
var defaultLicense | ||
var defaultLicenseFile | ||
export default function remarkLicense(options = {}) { | ||
const ignoreFinalDefinitions = | ||
options.ignoreFinalDefinitions === undefined || | ||
options.ignoreFinalDefinitions === null | ||
? true | ||
: options.ignoreFinalDefinitions | ||
const test = options.heading || licenseHeadingRegexp | ||
|
||
// eslint-disable-next-line complexity | ||
return async (tree, file) => { | ||
// Else is for stdin, typically not used. | ||
/* c8 ignore next */ | ||
const base = file.dirname ? path.resolve(file.cwd, file.dirname) : file.cwd | ||
const packageFile = await findUpOne('package.json', base) | ||
let defaultName | ||
let defaultUrl | ||
let defaultLicense | ||
let defaultLicenseFile | ||
|
||
// Skip package loading if we have all info in `options`. | ||
if (settings.url && settings.name && settings.license) { | ||
one() | ||
} else { | ||
fs.readFile(path.resolve(cwd, 'package.json'), onpackage) | ||
} | ||
|
||
if (settings.file) { | ||
one() | ||
} else { | ||
fs.readdir(cwd, onfiles) | ||
if (packageFile && (!options.url || !options.name || !options.license)) { | ||
await read(packageFile) | ||
const packageJson = JSON.parse(String(packageFile)) | ||
const author = | ||
typeof packageJson.author === 'string' | ||
? parse(packageJson.author) | ||
: packageJson.author || {} | ||
defaultLicense = packageJson.license | ||
defaultName = author.name | ||
defaultUrl = author.url | ||
} | ||
|
||
function onpackage(error, buf) { | ||
var pack = {} | ||
var author | ||
|
||
if (buf) { | ||
try { | ||
pack = JSON.parse(buf) | ||
} catch (error) { | ||
return one(error) | ||
if (!options.file) { | ||
const files = await fs.readdir( | ||
(packageFile && path.resolve(packageFile.cwd, packageFile.dirname)) || | ||
file.cwd | ||
) | ||
let index = -1 | ||
|
||
while (++index < files.length) { | ||
if (licenseRegexp.test(files[index])) { | ||
defaultLicenseFile = files[index] | ||
break | ||
} | ||
} | ||
|
||
// Hard to test. | ||
/* c8 ignore next 3 */ | ||
if (error && error.code !== 'ENOENT') { | ||
one(error) | ||
} else { | ||
defaultLicense = pack.license | ||
author = pack.author || {} | ||
author = typeof author === 'string' ? parse(author) : author | ||
defaultName = author.name | ||
defaultUrl = author.url | ||
|
||
one() | ||
} | ||
} | ||
|
||
function onfiles(error, files) { | ||
var length | ||
var index | ||
|
||
// Hard to test. | ||
/* c8 ignore next 3 */ | ||
if (error) { | ||
one(error) | ||
} else { | ||
length = files.length | ||
index = -1 | ||
|
||
while (++index < length) { | ||
if (licenseRegexp.test(files[index])) { | ||
defaultLicenseFile = files[index] | ||
break | ||
} | ||
} | ||
const url = options.url || defaultUrl | ||
const name = options.name || defaultName | ||
const license = options.license || defaultLicense | ||
let licenseFile = options.file || defaultLicenseFile | ||
|
||
one() | ||
} | ||
/* Ignore the license file itself. */ | ||
if (licenseFile && file.path === licenseFile) { | ||
return | ||
} | ||
|
||
function one(error) { | ||
if (error) { | ||
next(error) | ||
left = Infinity | ||
} else if (--left === 0) { | ||
done() | ||
} | ||
if (!license) { | ||
throw new Error( | ||
'Missing required `license` in settings.\n' + | ||
'Either add a `license` to a `package.json` file\n' + | ||
'or pass it into `remark-license`' | ||
) | ||
} | ||
|
||
function done() { | ||
var url = settings.url || defaultUrl | ||
var name = settings.name || defaultName | ||
var license = settings.license || defaultLicense | ||
var licenseFile = settings.file || defaultLicenseFile | ||
|
||
/* Ignore the license file itself. */ | ||
if (licenseFile && file.path === licenseFile) { | ||
return next() | ||
} | ||
if (!name) { | ||
throw new Error( | ||
'Missing required `name` in settings.\n' + | ||
'Either add an `author` to a `package.json` file\n' + | ||
'or pass it into `remark-license`' | ||
) | ||
} | ||
|
||
if (!license) { | ||
return next( | ||
new Error( | ||
'Missing required `license` in settings.\n' + | ||
'Either add a `license` to a `package.json` file\n' + | ||
'or pass it into `remark-license`' | ||
) | ||
) | ||
} | ||
if (!licenseFile && license in spdx) { | ||
licenseFile = spdx[license].url | ||
} | ||
|
||
if (!name) { | ||
return next( | ||
new Error( | ||
'Missing required `name` in settings.\n' + | ||
'Either add an `author` to a `package.json` file\n' + | ||
'or pass it into `remark-license`' | ||
) | ||
) | ||
} | ||
headingRange(tree, {ignoreFinalDefinitions, test}, (start, nodes, end) => { | ||
const children = [] | ||
const node = {type: 'paragraph', children} | ||
let parent | ||
|
||
if (!licenseFile && license in spdx) { | ||
licenseFile = spdx[license].url | ||
if (licenseFile) { | ||
parent = {type: 'link', title: null, url: licenseFile, children: []} | ||
children.push(parent) | ||
} else { | ||
parent = node | ||
} | ||
|
||
headingRange(tree, headingOptions, onheading) | ||
parent.children.push({type: 'text', value: license}) | ||
|
||
next() | ||
children.push({type: 'text', value: ' © '}) | ||
|
||
function onheading(start, nodes, end) { | ||
var children = [] | ||
var node = {type: 'paragraph', children: children} | ||
var link | ||
var parent | ||
if (url) { | ||
let link | ||
|
||
if (licenseFile) { | ||
parent = {type: 'link', title: null, url: licenseFile, children: []} | ||
children.push(parent) | ||
if ( | ||
url.slice(0, http.length) !== http && | ||
url.slice(0, https.length) !== https | ||
) { | ||
link = http + url | ||
} else { | ||
parent = node | ||
link = url | ||
} | ||
|
||
parent.children.push({type: 'text', value: license}) | ||
|
||
children.push({type: 'text', value: ' © '}) | ||
|
||
if (url) { | ||
if ( | ||
url.slice(0, http.length) !== http && | ||
url.slice(0, https.length) !== https | ||
) { | ||
link = http + url | ||
} else { | ||
link = url | ||
} | ||
|
||
parent = {type: 'link', title: null, url: link, children: []} | ||
children.push(parent) | ||
} else { | ||
parent = node | ||
} | ||
parent = {type: 'link', title: null, url: link, children: []} | ||
children.push(parent) | ||
} else { | ||
parent = node | ||
} | ||
|
||
parent.children.push({type: 'text', value: name}) | ||
parent.children.push({type: 'text', value: name}) | ||
|
||
return [start, node, end] | ||
} | ||
} | ||
return [start, node, end] | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters