@superdesk/build-tools 1.1.0 → 1.2.0-rc1
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/package.json +1 -1
- package/src/dev-link.js +138 -0
- package/src/index.js +3 -0
package/package.json
CHANGED
package/src/dev-link.js
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `dev-link` CLI command. Symlinks one or more local source repos into the
|
|
3
|
+
* current working directory's node_modules so a Superdesk template can be
|
|
4
|
+
* developed against unpublished local checkouts (e.g. superdesk-client-core,
|
|
5
|
+
* superdesk-planning) without using `npm link`.
|
|
6
|
+
*
|
|
7
|
+
* For each source path:
|
|
8
|
+
* 1. Read its package.json to get the package name. The symlink in
|
|
9
|
+
* node_modules uses this name, not the directory name (so
|
|
10
|
+
* superdesk-client-core correctly lands as node_modules/superdesk-core).
|
|
11
|
+
* 2. Run `npm install` in the source root, and also in any client/<subdir>
|
|
12
|
+
* that has its own package.json (covers superdesk-planning's nested
|
|
13
|
+
* client/planning-extension without hard-coding it).
|
|
14
|
+
* 3. Replace whatever is currently at node_modules/<package-name> with a
|
|
15
|
+
* symlink to the source's absolute path.
|
|
16
|
+
*
|
|
17
|
+
* Pre-condition: node_modules must already exist in the cwd. The command
|
|
18
|
+
* errors out otherwise to catch the common mistake of linking before the
|
|
19
|
+
* template's own `npm install` has run.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
const fs = require('fs');
|
|
23
|
+
const path = require('path');
|
|
24
|
+
const {execFileSync} = require('child_process');
|
|
25
|
+
|
|
26
|
+
function readPkg(dir) {
|
|
27
|
+
return JSON.parse(fs.readFileSync(path.join(dir, 'package.json'), 'utf-8'));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Returns every directory inside `sourceRoot` that contains a package.json
|
|
32
|
+
* we need to install. That is the root itself, plus any `client/*` subdir
|
|
33
|
+
* that ships its own package.json (covers the superdesk-planning layout
|
|
34
|
+
* where the host-build-relevant deps live under client/planning-extension).
|
|
35
|
+
*/
|
|
36
|
+
function findInstallTargets(sourceRoot) {
|
|
37
|
+
const targets = [];
|
|
38
|
+
|
|
39
|
+
if (fs.existsSync(path.join(sourceRoot, 'package.json'))) {
|
|
40
|
+
targets.push(sourceRoot);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const clientDir = path.join(sourceRoot, 'client');
|
|
44
|
+
|
|
45
|
+
if (fs.existsSync(clientDir) && fs.statSync(clientDir).isDirectory()) {
|
|
46
|
+
for (const entry of fs.readdirSync(clientDir, {withFileTypes: true})) {
|
|
47
|
+
if (!entry.isDirectory()) {
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const nestedPkg = path.join(clientDir, entry.name, 'package.json');
|
|
52
|
+
|
|
53
|
+
if (fs.existsSync(nestedPkg)) {
|
|
54
|
+
targets.push(path.join(clientDir, entry.name));
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return targets;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function npmInstall(dir) {
|
|
63
|
+
console.info(` installing dependencies in ${dir}`);
|
|
64
|
+
execFileSync('npm', ['install'], {stdio: 'inherit', cwd: dir});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function ensureSymlink(target, linkPath) {
|
|
68
|
+
let existing;
|
|
69
|
+
|
|
70
|
+
try {
|
|
71
|
+
existing = fs.lstatSync(linkPath);
|
|
72
|
+
} catch (e) {
|
|
73
|
+
if (e.code !== 'ENOENT') {
|
|
74
|
+
throw e;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (existing != null) {
|
|
79
|
+
if (existing.isSymbolicLink() || !existing.isDirectory()) {
|
|
80
|
+
fs.unlinkSync(linkPath);
|
|
81
|
+
} else {
|
|
82
|
+
fs.rmSync(linkPath, {recursive: true, force: true});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
fs.symlinkSync(target, linkPath, 'dir');
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function devLink(consumerDir, sources) {
|
|
90
|
+
const consumerNodeModules = path.join(consumerDir, 'node_modules');
|
|
91
|
+
|
|
92
|
+
if (!fs.existsSync(consumerNodeModules)) {
|
|
93
|
+
throw new Error(
|
|
94
|
+
`Consumer node_modules not found at ${consumerNodeModules}. `
|
|
95
|
+
+ 'Run `npm install` in the template first, then re-run dev-link.'
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
for (const source of sources) {
|
|
100
|
+
const sourceAbs = path.resolve(consumerDir, source);
|
|
101
|
+
|
|
102
|
+
if (!fs.existsSync(sourceAbs)) {
|
|
103
|
+
throw new Error(`Source path does not exist: ${sourceAbs}`);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const pkg = readPkg(sourceAbs);
|
|
107
|
+
const packageName = pkg.name;
|
|
108
|
+
|
|
109
|
+
if (packageName == null) {
|
|
110
|
+
throw new Error(`Source ${sourceAbs} has no name field in package.json`);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
console.info(`\n${packageName} <- ${sourceAbs}`);
|
|
114
|
+
|
|
115
|
+
for (const target of findInstallTargets(sourceAbs)) {
|
|
116
|
+
npmInstall(target);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const linkPath = path.join(consumerNodeModules, packageName);
|
|
120
|
+
|
|
121
|
+
ensureSymlink(sourceAbs, linkPath);
|
|
122
|
+
console.info(` linked node_modules/${packageName}`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function register(program, currentDir) {
|
|
127
|
+
program.command('dev-link <source...>')
|
|
128
|
+
.description(
|
|
129
|
+
'symlink one or more local source repos into the current node_modules '
|
|
130
|
+
+ 'for local development. Runs `npm install` in each source (and in any '
|
|
131
|
+
+ 'nested client/<extension> packages) before linking.'
|
|
132
|
+
)
|
|
133
|
+
.action((sources) => {
|
|
134
|
+
devLink(currentDir, sources);
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
module.exports = {register, devLink};
|
package/src/index.js
CHANGED
|
@@ -9,6 +9,7 @@ const installExtensions = require('./extensions/install-extensions');
|
|
|
9
9
|
const {mergeTranslationsFromExtensions} = require('./extensions/translations');
|
|
10
10
|
const {extractTranslations} = require('./extensions/extract-translations');
|
|
11
11
|
const {namespaceCSS, watchCSS} = require('./extensions/css');
|
|
12
|
+
const devLink = require('./dev-link');
|
|
12
13
|
|
|
13
14
|
const {Command} = require('commander');
|
|
14
15
|
const program = new Command();
|
|
@@ -108,5 +109,7 @@ extensions
|
|
|
108
109
|
|
|
109
110
|
program.addCommand(extensions);
|
|
110
111
|
|
|
112
|
+
devLink.register(program, currentDir);
|
|
113
|
+
|
|
111
114
|
program.version(require('../package.json').version);
|
|
112
115
|
program.parse(process.argv);
|