Skip to content

Commit 983f3e1

Browse files
committed
chore(tools): rework tools
1 parent 1d6d69c commit 983f3e1

File tree

11 files changed

+94
-87
lines changed

11 files changed

+94
-87
lines changed

tools/proto/package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@
1212
"email": "gerkin@knodes.org",
1313
"name": "GerkinDev"
1414
},
15-
"keywords": ["typedoc","documentation"],
15+
"keywords": [
16+
"typedoc",
17+
"documentation"
18+
],
1619
"main": "dist/index.js",
1720
"files": [
1821
"src",
Lines changed: 12 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,15 @@
1-
const assert = require( 'assert' );
2-
const { readFile, writeFile } = require( 'fs/promises' );
1+
const { readFile } = require( 'fs/promises' );
32
const { resolve } = require( 'path' );
43

54
const { memoize, cloneDeep, defaultsDeep, uniq } = require( 'lodash' );
65
const semver = require( 'semver' );
7-
const { normalizePath } = require( 'typedoc' );
86

9-
const { readProjectPackageJson, getDocsUrl, assertDiffFile } = require( './utils' );
10-
const { formatPackages, resolveRoot } = require( '../utils' );
7+
const { syncFile, formatPackage, getDocsUrl } = require( './utils' );
8+
const { resolveRoot } = require( '../utils' );
119

1210
/**
1311
* @param {boolean} checkOnly
14-
* @returns {import('./utils').ProtoHandler<{getProtoPkg: (v: string) => string, rootJson: any, rootJsonStr: string, rootPath: string}}
12+
* @returns {import('./utils').ProtoHandler<{getProtoPkg: (v: string) => Promise<string>, rootJson: any, rootJsonStr: string, rootPath: string}}
1513
*/
1614
module.exports.packageJson = async checkOnly => ( {
1715
setup: async () => {
@@ -21,27 +19,22 @@ module.exports.packageJson = async checkOnly => ( {
2119
const rootJson = JSON.parse( rootJsonStr );
2220
return { getProtoPkg, rootJson, rootJsonStr, rootPath };
2321
},
24-
run: async ( proto, { path: projectPath }, projects, _, { getProtoPkg, rootJson: rootPackageJson } ) => {
25-
const { packageContent = {}, path: packagePath } = await readProjectPackageJson( projectPath ) ?? {};
22+
run: async ( proto, { path: projectPath, pkgJsonPath, pkgJson }, projects, _, { getProtoPkg, rootJson: rootPackageJson } ) => {
2623
const protoPkgContent = await getProtoPkg( proto );
2724
const protoPkg = JSON.parse( protoPkgContent
2825
.replace( /\{projectRelDir\}/g, projectPath )
29-
.replace( /\{projectTypeDocUrl\}/g, getDocsUrl( packageContent ) ) );
30-
const newProjectPkg = defaultsDeep( cloneDeep( protoPkg ), packageContent );
26+
.replace( /\{projectTypeDocUrl\}/g, getDocsUrl( pkgJson ) ) );
27+
const newProjectPkg = defaultsDeep( cloneDeep( protoPkg ), pkgJson );
3128
[ 'keywords', 'files' ].forEach( prop => newProjectPkg[prop] = uniq( [
3229
...( protoPkg[prop] ?? [] ),
33-
...( packageContent[prop] ?? [] ),
30+
...( pkgJson[prop] ?? [] ),
3431
]
3532
.map( k => k.toLowerCase() ) )
3633
.sort() );
37-
if( checkOnly ){
38-
assert.deepStrictEqual( newProjectPkg, packageContent );
39-
} else {
40-
await writeFile( packagePath, JSON.stringify( newProjectPkg, null, 2 ) );
41-
}
34+
await syncFile( checkOnly, pkgJsonPath, await formatPackage( newProjectPkg ) );
4235

4336
rootPackageJson['devDependencies'] = rootPackageJson['devDependencies'] ?? {};
44-
Object.entries( packageContent )
37+
Object.entries( syncFile )
4538
.filter( ( [ k ] ) => k.toLowerCase().includes( 'dependencies' ) )
4639
.forEach( ( [ k, v ] ) => {
4740
const rootPkgDeps = rootPackageJson['devDependencies'] ?? {};
@@ -64,22 +57,12 @@ module.exports.packageJson = async checkOnly => ( {
6457
};
6558
} );
6659
},
67-
tearDown: async( proto, projects, _, { rootJson: rootJson, rootJsonStr: rootJsonStr, rootPath } ) => {
60+
tearDown: async( proto, projects, _, { rootJson, rootPath } ) => {
6861
rootJson['devDependencies'] = {
6962
...rootJson['devDependencies'],
7063
...Object.fromEntries( projects.map( p => [ p.pkgName, `file:${p.path}` ] ) ),
7164
};
72-
await writeFile( rootPath, `${JSON.stringify( rootJson, null, 2 ) }\n` );
73-
if( checkOnly ){
74-
try {
75-
await formatPackages( rootPath );
76-
await assertDiffFile( rootPath, rootJsonStr, true );
77-
} finally {
78-
await writeFile( rootPath, rootJsonStr );
79-
}
80-
} else {
81-
await formatPackages( rootPath, ...projects.map( p => normalizePath( resolve( p.path, 'package.json' ) ) ) );
82-
}
65+
await syncFile( checkOnly, rootPath, await formatPackage( rootJson ) );
8366
},
8467
handleFile: filename => /(\/|^)package\.json$/.test( filename ),
8568
} );

tools/sync-proto-modules/readme.js

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,24 @@
11
const { yellow } = require( 'chalk' );
22
const { glob } = require( 'glob' );
33

4-
const { tryReadFile, getDocsUrl, readProjectPackageJson, syncFile } = require( './utils' );
4+
const { tryReadFile, getDocsUrl, syncFile } = require( './utils' );
55

66
class Readme {
77
constructor( checkOnly ){
88
this.name = 'readme';
99
this.checkOnly = checkOnly;
1010
}
1111

12-
async run( _proto, { path: projectPath } ){
12+
async run( _proto, { path: projectPath, pkgJson } ){
1313
const readmeFiles = await glob( `${projectPath}/@(readme|README).@(md|MD)` );
1414
if( readmeFiles.length > 1 ){
1515
throw new Error( 'Multiple README files' );
1616
}
1717
const readmeFile = readmeFiles[0] ?? `${projectPath}/README.md`;
1818
const readmeContent = ( await tryReadFile( readmeFile, 'utf-8' ) ) ?? '';
19-
const { packageContent } = await readProjectPackageJson( projectPath );
20-
if( !packageContent ){
21-
throw new Error();
22-
}
2319
const result = ( await [ this._replaceHeader, this._replaceInstall ].reduce( async ( content, fn ) => {
2420
const c = await content;
25-
return fn( c, packageContent );
21+
return fn( c, pkgJson );
2622
}, Promise.resolve( readmeContent ) ) ).replace( /\r\n/g, '\n' );
2723
await syncFile( this.checkOnly, readmeFile, result );
2824
}

tools/sync-proto-modules/sync-fs.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
const assert = require( 'assert' );
22
const { createHash } = require( 'crypto' );
3-
const { readFile, mkdir, access, copyFile, unlink, writeFile } = require( 'fs/promises' );
3+
const { readFile, mkdir, access, copyFile, unlink } = require( 'fs/promises' );
44

55
const { resolve, join } = require( 'path' );
66

77
const { bold } = require( 'chalk' );
88
const { glob } = require( 'glob' );
99
const { memoize, partition, isString } = require( 'lodash' );
1010

11-
const { tryReadFile } = require( './utils' );
11+
const { syncFile, tryReadFile } = require( './utils' );
1212

1313
const checksum = async file => createHash( 'md5' )
1414
.update( ( await readFile( file, 'utf-8' ) ).replace( /\r?\n/g, '\n' ), 'utf-8' )
@@ -140,7 +140,7 @@ module.exports.syncFs = checkOnly => {
140140
...cache,
141141
...changed,
142142
};
143-
await writeFile( cacheFile, Object.entries( newCache )
143+
await syncFile( checkOnly, cacheFile, Object.entries( newCache )
144144
.filter( ( [ , v ] ) => isString( v ) )
145145
.map( entry => entry.join( ' :: ' ) )
146146
.join( '\n' ) );
Lines changed: 38 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,46 @@
1-
const assert = require( 'assert' );
1+
const { resolve } = require( 'path' );
22

3-
const { spawn, captureStream, resolveRoot } = require( '../utils' );
3+
const { SemVer } = require( 'semver' );
4+
5+
const { syncFile } = require( './utils/diff' );
6+
const { formatPackage } = require( './utils/package-json' );
7+
const { resolveRoot } = require( '../utils' );
8+
9+
/**
10+
* @param {boolean} checkOnly
11+
* @param {SemVer} version
12+
* @returns {<T extends {}>(pkg: T, path: string) => Promise<T>}
13+
*/
14+
const syncPkgTypedocVersion = ( checkOnly, version ) => async ( pkg, path ) => {
15+
if( 'typedoc' in pkg.dependencies ){
16+
pkg.dependencies.typedoc = `^${version.major}.${version.minor}.0`;
17+
}
18+
if( 'typedoc' in pkg.peerDependencies ){
19+
pkg.peerDependencies.typedoc = `^${version.major}.${version.minor}.0`;
20+
}
21+
if( 'typedoc' in pkg.devDependencies ){
22+
pkg.devDependencies.typedoc = `^${version.format()}`;
23+
}
24+
await syncFile( checkOnly, path, await formatPackage( pkg ) );
25+
return pkg;
26+
};
427

528
/**
629
* @param {boolean} checkOnly
7-
* @returns {import('./utils').ProtoHandler}
30+
* @returns {import('./utils').ProtoHandler<ReturnType<typeof syncPkgTypedocVersion>>}
831
*/
932
module.exports.typedocSubmodule = async checkOnly => ( {
10-
tearDown: async () => {
11-
const typedocDir = resolveRoot( 'typedoc' );
12-
const packageTypedoc = require( '../../package.json' ).devDependencies.typedoc.replace( /^\D*/, '' );
13-
const submoduleTypedoc = ( await spawn(
14-
'git',
15-
[ '-C', typedocDir, 'describe', '--tags' ],
16-
{ stdio: [ null, captureStream(), captureStream() ] } ) )
17-
.stdout.trim().replace( /^v/, '' );
18-
if( checkOnly ){
19-
assert.equal( packageTypedoc, submoduleTypedoc, `The packages typedoc version ${packageTypedoc} does not match the submodule typedoc version ${submoduleTypedoc}` );
20-
} else if( packageTypedoc !== submoduleTypedoc ){
21-
console.log( 'Moving typedoc to the expected tag' );
22-
await spawn(
23-
'git',
24-
[ '-C', typedocDir, 'fetch', '--tags' ] );
25-
await spawn(
26-
'git',
27-
[ '-C', typedocDir, 'switch', `tags/v${packageTypedoc}`, '--detach' ] );
28-
}
33+
setup: async proto => {
34+
const submoduleDir = resolveRoot( 'typedoc' );
35+
const submoduleVersion = require( resolve( submoduleDir, 'package.json' ) ).version;
36+
const doSync = syncPkgTypedocVersion( checkOnly, new SemVer( submoduleVersion ) );
37+
const protoPkgPath = resolve( proto, 'package.json' );
38+
const protoPkgJson = require( protoPkgPath );
39+
await doSync( protoPkgJson, protoPkgPath );
40+
return doSync;
41+
},
42+
run: async ( proto, project, projects, handlers, doSync ) => {
43+
const syncedPkg = await doSync( project.pkgJson, project.pkgJsonPath );
44+
Object.assign( project.pkgJson, syncedPkg );
2945
},
3046
} );

tools/sync-proto-modules/utils/diff.js

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
const { writeFile, readFile } = require( 'fs/promises' );
22

3-
const { bgRed, bgGreen, grey, bold } = require( 'chalk' );
3+
const { bgRed, bgGreen, grey, bold, bgGrey } = require( 'chalk' );
44
const Diff = require( 'diff' );
55
const { pad } = require( 'lodash' );
66

7+
const { relativeToRoot } = require( '../../utils' );
8+
79
const linesCount = str => ( str.match( /\n/g )?.length ?? 0 ) + 1;
810
const formatNl = fn => ( str, newLine = true ) => fn( str === '' && newLine ? '↵' : str );
911

@@ -38,14 +40,17 @@ const getLinesDiff = ( { lines, color, printLine, sameLine, isAdd, totalLines0,
3840
return lines.join( '\n' );
3941
};
4042

43+
const errors = [];
4144
module.exports.assertDiffFile = async ( filename, expectedContent, invert = false ) => {
4245
const actualContent = await readFile( filename, 'utf-8' );
4346

44-
const diff = Diff.diffWords( expectedContent, actualContent );
47+
const diff = Diff.diffLines( expectedContent, actualContent );
4548
if( diff.length === 1 ){
4649
return;
4750
}
4851

52+
console.log( bgGrey( relativeToRoot( filename ) ) );
53+
4954
let line = 1;
5055
let lineDelta = 0;
5156
let sameLine = false;
@@ -81,7 +86,13 @@ module.exports.assertDiffFile = async ( filename, expectedContent, invert = fals
8186
}
8287
} );
8388
console.log();
84-
throw new Error( `File ${filename} does not match the expected content` );
89+
errors.push( new Error( `File ${filename} does not match the expected content` ) );
90+
};
91+
module.exports.summarizeErrors = () => {
92+
if( errors.length ){
93+
// eslint-disable-next-line no-undef -- Actually exists
94+
throw new AggregateError( errors, 'Some files are incorrect' );
95+
}
8596
};
8697

8798
module.exports.syncFile = async ( checkOnly, filename, expectedContent ) => {

tools/sync-proto-modules/utils/index.js

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
const assert = require( 'assert' );
22

33
const { readFile } = require( 'fs/promises' );
4-
const { resolve } = require( 'path' );
54

65
const SemVer = require( 'semver' );
76

@@ -36,24 +35,9 @@ module.exports.getDocsUrl = pkgJson => {
3635
return `${docsUrl}/modules/${( pkgJson.name ?? assert.fail( 'No name' ) ).replace( /[^a-z0-9]/gi, '_' )}.html`;
3736
};
3837

39-
module.exports.readProjectPackageJson = async projectPath => {
40-
const projectPkgPath = resolve( projectPath, 'package.json' );
41-
const content = await module.exports.tryReadFile( projectPkgPath );
42-
if( content ){
43-
return {
44-
packageContent: JSON.parse( content ),
45-
path: projectPkgPath,
46-
};
47-
} else {
48-
return {
49-
packageContent: undefined,
50-
path: projectPkgPath,
51-
};
52-
}
53-
};
54-
5538
module.exports = {
5639
...module.exports,
5740
...require( './yaml' ),
5841
...require( './diff' ),
42+
...require( './package-json' ),
5943
};
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
const format = require( 'format-package' ).default;
2+
3+
module.exports.formatPackage = async content => {
4+
if( typeof content === 'string' ){
5+
content = JSON.parse( content );
6+
}
7+
return format( content, {} );
8+
};

tools/sync-proto-modules/utils/yaml.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ const { parseDocument: parseYamlDocument, visit, stringify: stringifyYaml, YAMLS
66
const resolveRefFactory = ( anchorsMap, vars ) => ( ref, src ) => {
77
if( ref.startsWith( '*' ) ){
88
const node = anchorsMap[ref.slice( 1 )]?.clone() ??
9-
assert.fail( `Missing alias "${ref}" in expression "${JSON.stringify( src )}"` );
9+
assert.fail( `Missing alias "${ref}" in expression "${JSON.stringify( src )}"` );
1010
node.anchor = undefined;
1111
return {
1212
'': () => stringifyYaml( node ).trim(),
@@ -18,7 +18,7 @@ const resolveRefFactory = ( anchorsMap, vars ) => ( ref, src ) => {
1818
};
1919
} else {
2020
const val = vars[ref] ??
21-
assert.fail( `Missing variable "${ref}" in expression "${JSON.stringify( src )}"` );
21+
assert.fail( `Missing variable "${ref}" in expression "${JSON.stringify( src )}"` );
2222
return {
2323
'': () => val,
2424
'!': () => val.toString(),

tools/sync-proto.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const { packageJson } = require( './sync-proto-modules/package-json' );
99
const { readme } = require( './sync-proto-modules/readme' );
1010
const { syncFs } = require( './sync-proto-modules/sync-fs' );
1111
const { typedocSubmodule } = require( './sync-proto-modules/typedoc-submodule' );
12+
const { summarizeErrors } = require( './sync-proto-modules/utils' );
1213
const { selectProjects, createStash } = require( './utils' );
1314

1415
if( require.main === module ){
@@ -35,9 +36,9 @@ if( require.main === module ){
3536
const initialValue = Promise.resolve( [] );
3637
const handlers = await [
3738
syncFs,
39+
typedocSubmodule,
3840
packageJson,
3941
readme,
40-
typedocSubmodule,
4142
circleCi,
4243
changelog,
4344
issueTemplate,
@@ -55,6 +56,7 @@ if( require.main === module ){
5556
for( const handler of handlers ){
5657
await handler.tearDown?.( protoDir, projects, handlers, setups.get( handler ) );
5758
}
59+
summarizeErrors();
5860
} catch( e ){
5961
console.error( e );
6062
process.exit( 1 );

0 commit comments

Comments
 (0)