js-build-tools 5.3.0 → 5.3.1
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 +26 -0
- package/dist/build.js +63 -63
- package/dist/partials/imagesFor.js +42 -48
- package/dist/partials/loadPeer.js +99 -0
- package/dist/partials/standardLint.js +73 -75
- package/dist/partials/tsFor.js +70 -82
- package/dist/partials/typeDocsFor.js +35 -21
- package/dist/partials.js +19 -0
- package/dist/partials.min.js +1 -1
- package/dist/typeDocs.js +9 -9
- package/functions/partials/imagesFor.mjs +7 -13
- package/functions/partials/loadPeer.mjs +75 -0
- package/functions/partials/loadPeer.test.mjs +58 -0
- package/functions/partials/standardLint.mjs +3 -5
- package/functions/partials/tsFor.mjs +4 -20
- package/functions/partials/typeDocsFor.mjs +27 -22
- package/functions/partials/typeDocsFor.test.mjs +26 -5
- package/functions/partials.mjs +1 -0
- package/functions/partials.test.mjs +1 -1
- package/gulp.config.mjs +2 -2
- package/package.json +1 -1
|
@@ -1,16 +1,11 @@
|
|
|
1
1
|
import fs from 'node:fs'
|
|
2
2
|
import os from 'node:os'
|
|
3
3
|
import path from 'node:path'
|
|
4
|
-
import { createRequire } from 'node:module'
|
|
5
|
-
import { pathToFileURL } from 'node:url'
|
|
6
4
|
import * as gulpConfig from '../../gulp.config.mjs'
|
|
5
|
+
import { importPeer } from './loadPeer.mjs'
|
|
7
6
|
import { loadTypescript } from './tsFor.mjs'
|
|
8
7
|
import { removeDirectory } from './removeDirectory.mjs'
|
|
9
8
|
|
|
10
|
-
// TypeDoc ships ESM-only, and this project also compiles itself to a CommonJS build (see tsFor.mjs, which hides its
|
|
11
|
-
// own import of gulp-ts-compile the same way), so the import() is hidden from babel's CommonJS transform.
|
|
12
|
-
const importModule = new Function('specifier', 'return import(specifier)')
|
|
13
|
-
|
|
14
9
|
const installHint = 'Install it in your project with: npm install --save-dev typedoc'
|
|
15
10
|
|
|
16
11
|
/**
|
|
@@ -21,18 +16,7 @@ const installHint = 'Install it in your project with: npm install --save-dev typ
|
|
|
21
16
|
* @returns {Promise<Object>} The TypeDoc module.
|
|
22
17
|
* @throws {Error} With install instructions when typedoc is not installed.
|
|
23
18
|
*/
|
|
24
|
-
export const loadTypeDoc =
|
|
25
|
-
let typeDocPath
|
|
26
|
-
try {
|
|
27
|
-
typeDocPath = createRequire(path.join(projectPath, 'package.json')).resolve('typedoc')
|
|
28
|
-
} catch (error) {
|
|
29
|
-
if (error.code === 'MODULE_NOT_FOUND') {
|
|
30
|
-
throw new Error(`The docs task needs the optional peer dependency typedoc, which is not installed. ${installHint}`)
|
|
31
|
-
}
|
|
32
|
-
throw error
|
|
33
|
-
}
|
|
34
|
-
return importModule(pathToFileURL(typeDocPath).href)
|
|
35
|
-
}
|
|
19
|
+
export const loadTypeDoc = (projectPath = process.cwd()) => importPeer('typedoc', { task: 'docs', installHint, projectPath })
|
|
36
20
|
|
|
37
21
|
const isSource = fileName => /\.(ts|tsx|mts|cts)$/.test(fileName) && !/\.d\.[cm]?ts$/.test(fileName) && !/\.(test|spec)\./.test(fileName)
|
|
38
22
|
|
|
@@ -86,12 +70,30 @@ export const describeExports = (ts, filePath) => {
|
|
|
86
70
|
return { hasDefault, hasNamed }
|
|
87
71
|
}
|
|
88
72
|
|
|
73
|
+
/**
|
|
74
|
+
* The description of a folder for its module: the first doc comment of the folder's index file, without its tags
|
|
75
|
+
* (@module, @file, ...), or an empty string when there is none.
|
|
76
|
+
* @memberOf module:partials
|
|
77
|
+
* @param {string} folderPath
|
|
78
|
+
* @returns {string}
|
|
79
|
+
*/
|
|
80
|
+
export const describeFolder = folderPath => {
|
|
81
|
+
const indexFile = ['index.ts', 'index.tsx', 'index.mts', 'index.cts'].map(name => path.join(folderPath, name)).find(file => fs.existsSync(file))
|
|
82
|
+
const comment = indexFile && fs.readFileSync(indexFile, 'utf8').match(/^\s*\/\*\*([\s\S]*?)\*\//)
|
|
83
|
+
if (!comment) {
|
|
84
|
+
return ''
|
|
85
|
+
}
|
|
86
|
+
const lines = comment[1].split('\n').map(line => line.replace(/^\s*\* ?/, '').trimEnd())
|
|
87
|
+
const tagAt = lines.findIndex(line => /^@\w+/.test(line))
|
|
88
|
+
return (tagAt === -1 ? lines : lines.slice(0, tagAt)).join('\n').trim()
|
|
89
|
+
}
|
|
90
|
+
|
|
89
91
|
/**
|
|
90
92
|
* Write one entry file per folder of the source directory into the entry directory. TypeDoc makes a module of every
|
|
91
93
|
* entry file, so the modules of the documentation mirror the folders. The default export of each source file is
|
|
92
94
|
* re-exported under the name of the file (the source files hold one function each), and anything else a file exports
|
|
93
95
|
* is re-exported as it is (that is where the types.ts files go). Index files (the barrels), tests and declaration
|
|
94
|
-
* files are left out. A source directory with no folders gets a single entry called index.
|
|
96
|
+
* files are left out, but the first doc comment of a folder's index file becomes the description of its module. A source directory with no folders gets a single entry called index.
|
|
95
97
|
* @memberOf module:partials
|
|
96
98
|
* @param {Object} ts - The TypeScript compiler API.
|
|
97
99
|
* @param {string} srcDir - The directory holding the TypeScript source.
|
|
@@ -103,11 +105,11 @@ export const writeDocEntries = (ts, srcDir, entryDir) => {
|
|
|
103
105
|
fs.mkdirSync(entryDir, { recursive: true })
|
|
104
106
|
const folders = fs.readdirSync(absoluteSrc, { withFileTypes: true })
|
|
105
107
|
.filter(entry => entry.isDirectory() && entry.name !== 'node_modules')
|
|
106
|
-
.map(entry => ({ name: entry.name, files: listSources(path.join(absoluteSrc, entry.name)) }))
|
|
108
|
+
.map(entry => ({ name: entry.name, path: path.join(absoluteSrc, entry.name), files: listSources(path.join(absoluteSrc, entry.name)) }))
|
|
107
109
|
.filter(folder => folder.files.length)
|
|
108
110
|
const groups = folders.length
|
|
109
111
|
? folders
|
|
110
|
-
: [{ name: 'index', files: listSources(absoluteSrc).filter(file => !/^(index|main)\./.test(path.basename(file))) }]
|
|
112
|
+
: [{ name: 'index', path: absoluteSrc, files: listSources(absoluteSrc).filter(file => !/^(index|main)\./.test(path.basename(file))) }]
|
|
111
113
|
return groups.map(group => {
|
|
112
114
|
const lines = group.files
|
|
113
115
|
.filter(file => !/^index\./.test(path.basename(file)))
|
|
@@ -121,8 +123,11 @@ export const writeDocEntries = (ts, srcDir, entryDir) => {
|
|
|
121
123
|
...(hasNamed ? [`export * from '${modulePath}'`] : [])
|
|
122
124
|
]
|
|
123
125
|
})
|
|
126
|
+
const description = group.path ? describeFolder(group.path) : ''
|
|
127
|
+
// TypeDoc takes the first comment of an entry file which has the @module tag as the description of the module
|
|
128
|
+
const moduleComment = description ? `/**\n${description.split('\n').map(line => ` * ${line}`.trimEnd()).join('\n')}\n * @module\n */\n\n` : ''
|
|
124
129
|
const entryPath = path.join(entryDir, `${group.name}.ts`)
|
|
125
|
-
fs.writeFileSync(entryPath, lines.join('\n') + '\n')
|
|
130
|
+
fs.writeFileSync(entryPath, moduleComment + lines.join('\n') + '\n')
|
|
126
131
|
return entryPath
|
|
127
132
|
})
|
|
128
133
|
}
|
|
@@ -2,7 +2,7 @@ import fs from 'fs'
|
|
|
2
2
|
import path from 'node:path'
|
|
3
3
|
import ts from 'typescript'
|
|
4
4
|
import * as setUp from '../test-helpers/setUp.mjs'
|
|
5
|
-
import { describeExports, loadTypeDoc, typeDocsFor, writeDocEntries } from './typeDocsFor.mjs'
|
|
5
|
+
import { describeExports, describeFolder, loadTypeDoc, typeDocsFor, writeDocEntries } from './typeDocsFor.mjs'
|
|
6
6
|
|
|
7
7
|
setUp.setDefaults('test-type-docs-for')
|
|
8
8
|
const gulpConfig = setUp.gulpConfig
|
|
@@ -19,7 +19,7 @@ beforeEach(
|
|
|
19
19
|
write(`${srcPath}/point/add.ts`, '/** Add two numbers. */\nconst add = (a: number, b: number): number => a + b\n\nexport default add\n')
|
|
20
20
|
write(`${srcPath}/point/get-name.ts`, 'export default function getName (): string { return "name" }\n')
|
|
21
21
|
write(`${srcPath}/point/types.ts`, 'export interface Point { x: number, y: number }\nexport type Axis = keyof Point\n')
|
|
22
|
-
write(`${srcPath}/point/index.ts`, "
|
|
22
|
+
write(`${srcPath}/point/index.ts`, "/**\n * Points of a matrix and the maths on them.\n * A second line.\n * @file Not part of the description\n * @module point\n */\nimport add from './add'\nexport default { add }\n")
|
|
23
23
|
write(`${srcPath}/point/add.test.ts`, "test('adds', () => {})\n")
|
|
24
24
|
write(`${srcPath}/point/add.d.ts`, 'export {}\n')
|
|
25
25
|
write(`${srcPath}/line/length.ts`, 'export const length = 5\nexport default length\n')
|
|
@@ -54,6 +54,18 @@ describe('describeExports', () => {
|
|
|
54
54
|
})
|
|
55
55
|
})
|
|
56
56
|
|
|
57
|
+
describe('describeFolder', () => {
|
|
58
|
+
test('is the text of the first comment of the index file, without its tags', () => {
|
|
59
|
+
expect(describeFolder(`${gulpConfig.get('srcPath')}/point`)).toBe('Points of a matrix and the maths on them.\nA second line.')
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
test('is empty without an index file, or a comment in it', () => {
|
|
63
|
+
expect(describeFolder(`${gulpConfig.get('srcPath')}/line`)).toBe('')
|
|
64
|
+
write(`${gulpConfig.get('srcPath')}/bare/index.ts`, "import a from './a'\nexport default { a }\n")
|
|
65
|
+
expect(describeFolder(`${gulpConfig.get('srcPath')}/bare`)).toBe('')
|
|
66
|
+
})
|
|
67
|
+
})
|
|
68
|
+
|
|
57
69
|
describe('writeDocEntries', () => {
|
|
58
70
|
test('writes one entry file for each folder which has source', () => {
|
|
59
71
|
const entryDir = `${gulpConfig.get('srcPath')}/../entries`
|
|
@@ -65,12 +77,13 @@ describe('writeDocEntries', () => {
|
|
|
65
77
|
const entryDir = `${gulpConfig.get('srcPath')}/../entries`
|
|
66
78
|
writeDocEntries(ts, gulpConfig.get('srcPath'), entryDir)
|
|
67
79
|
const absoluteSrc = path.resolve(gulpConfig.get('srcPath')).split(path.sep).join('/')
|
|
68
|
-
|
|
80
|
+
const exportLines = file => fs.readFileSync(file, 'utf8').trim().split('\n').filter(line => line.startsWith('export'))
|
|
81
|
+
expect(exportLines(`${entryDir}/point.ts`)).toEqual([
|
|
69
82
|
`export { default as add } from '${absoluteSrc}/point/add'`,
|
|
70
83
|
`export { default as getName } from '${absoluteSrc}/point/get-name'`,
|
|
71
84
|
`export * from '${absoluteSrc}/point/types'`
|
|
72
85
|
])
|
|
73
|
-
expect(
|
|
86
|
+
expect(exportLines(`${entryDir}/line.ts`)).toEqual([
|
|
74
87
|
`export { default as length } from '${absoluteSrc}/line/length'`,
|
|
75
88
|
`export * from '${absoluteSrc}/line/length'`
|
|
76
89
|
])
|
|
@@ -80,7 +93,15 @@ describe('writeDocEntries', () => {
|
|
|
80
93
|
const entryDir = `${gulpConfig.get('srcPath')}/../entries`
|
|
81
94
|
writeDocEntries(ts, gulpConfig.get('srcPath'), entryDir)
|
|
82
95
|
const entry = fs.readFileSync(`${entryDir}/point.ts`, 'utf8')
|
|
83
|
-
expect(entry).not.toMatch(/index|\.test|add\.d/)
|
|
96
|
+
expect(entry).not.toMatch(/from '.*(index|\.test|add\.d)/)
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
test('describes the module with the first comment of the index file of the folder', () => {
|
|
100
|
+
const entryDir = `${gulpConfig.get('srcPath')}/../entries`
|
|
101
|
+
writeDocEntries(ts, gulpConfig.get('srcPath'), entryDir)
|
|
102
|
+
expect(fs.readFileSync(`${entryDir}/point.ts`, 'utf8')).toMatch(/^\/\*\*\n \* Points of a matrix and the maths on them\.\n \* A second line\.\n \* @module\n \*\/\n\nexport/)
|
|
103
|
+
// A folder without an index file has no comment
|
|
104
|
+
expect(fs.readFileSync(`${entryDir}/line.ts`, 'utf8').startsWith('export')).toBe(true)
|
|
84
105
|
})
|
|
85
106
|
|
|
86
107
|
test('makes one entry called index when the source has no folders', () => {
|
package/functions/partials.mjs
CHANGED
|
@@ -15,6 +15,7 @@ export { distFor } from './partials/distFor.mjs'
|
|
|
15
15
|
export { distForSrc } from './partials/distForSrc.mjs'
|
|
16
16
|
export { distSeries } from './partials/distSeries.mjs'
|
|
17
17
|
export { imagesFor } from './partials/imagesFor.mjs'
|
|
18
|
+
export { importModule, importPeer, requirePeer } from './partials/loadPeer.mjs'
|
|
18
19
|
export { minifyFor } from './partials/minifyFor.mjs'
|
|
19
20
|
export { readmeTemplate } from './partials/readmeTemplate.mjs'
|
|
20
21
|
export { removeDirectory } from './partials/removeDirectory.mjs'
|
package/gulp.config.mjs
CHANGED
|
@@ -49,8 +49,8 @@ import { fileExists } from 'test-filesystem'
|
|
|
49
49
|
* Configurations for building the browser files.
|
|
50
50
|
* @typedef {Object<string, Setting>} module:gulpConfig~BrowserConfig
|
|
51
51
|
* @property {BooleanSetting} enabled - 'true' to generate browser bundled files; 'false' for node environment only
|
|
52
|
-
* @property {StringSetting} from - The
|
|
53
|
-
* @property {StringSetting} name - The
|
|
52
|
+
* @property {StringSetting} from - The search pattern used for retrieving compiled distribution files.
|
|
53
|
+
* @property {StringSetting} name - The name to use for the browser-bundled output file (.js will be appended).
|
|
54
54
|
* @property {StringSetting} to - The output directory for browser-bundled files.
|
|
55
55
|
* @property {ArrayableSetting} ignore - Module names or file paths which resolve to an empty object ({}) in the
|
|
56
56
|
* bundle instead of their real contents. For a dependency which is only reached because it is the default value of
|