UNPKG

13.9 kBJavaScriptView Raw
1"use strict";
2/* -----------------------------------------------------------------------------
3| Copyright (c) Jupyter Development Team.
4| Distributed under the terms of the Modified BSD License.
5|----------------------------------------------------------------------------*/
6var __importStar = (this && this.__importStar) || function (mod) {
7 if (mod && mod.__esModule) return mod;
8 var result = {};
9 if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
10 result["default"] = mod;
11 return result;
12};
13Object.defineProperty(exports, "__esModule", { value: true });
14/**
15 * Ensure the integrity of the packages in the repo.
16 *
17 * Ensure the core package version dependencies match everywhere.
18 * Ensure imported packages match dependencies.
19 * Ensure a consistent version of all packages.
20 * Manage the metapackage meta package.
21 */
22const path = __importStar(require("path"));
23const utils = __importStar(require("./utils"));
24const ensure_package_1 = require("./ensure-package");
25// Data to ignore.
26const MISSING = {
27 '@jupyterlab/buildutils': ['path'],
28 '@jupyterlab/testutils': ['fs'],
29 '@jupyterlab/vega5-extension': ['vega-embed']
30};
31const UNUSED = {
32 '@jupyterlab/apputils': ['@types/react'],
33 '@jupyterlab/application': ['@fortawesome/fontawesome-free'],
34 '@jupyterlab/apputils-extension': ['es6-promise'],
35 '@jupyterlab/services': ['node-fetch', 'ws'],
36 '@jupyterlab/rendermime': ['@jupyterlab/mathjax2'],
37 '@jupyterlab/testutils': [
38 'node-fetch',
39 'identity-obj-proxy',
40 'jest-raw-loader',
41 'markdown-loader-jest',
42 'jest-junit',
43 'jest-summary-reporter'
44 ],
45 '@jupyterlab/test-csvviewer': ['csv-spectrum'],
46 '@jupyterlab/vega5-extension': ['vega', 'vega-lite'],
47 '@jupyterlab/ui-components': ['@blueprintjs/icons']
48};
49// Packages that are allowed to have differing versions
50const DIFFERENT_VERSIONS = ['vega-lite', 'vega', 'vega-embed'];
51const SKIP_CSS = {
52 '@jupyterlab/application': ['@jupyterlab/rendermime'],
53 '@jupyterlab/application-extension': ['@jupyterlab/apputils'],
54 '@jupyterlab/completer': ['@jupyterlab/codeeditor'],
55 '@jupyterlab/docmanager': ['@jupyterlab/statusbar'],
56 '@jupyterlab/docregistry': [
57 '@jupyterlab/codeeditor',
58 '@jupyterlab/codemirror',
59 '@jupyterlab/rendermime' // Only used for model
60 ],
61 '@jupyterlab/documentsearch': [
62 '@jupyterlab/cells',
63 '@jupyterlab/codeeditor',
64 '@jupyterlab/codemirror',
65 '@jupyterlab/fileeditor',
66 '@jupyterlab/notebook'
67 ],
68 '@jupyterlab/filebrowser': ['@jupyterlab/statusbar'],
69 '@jupyterlab/fileeditor': ['@jupyterlab/statusbar'],
70 '@jupyterlab/help-extension': ['@jupyterlab/application'],
71 '@jupyterlab/shortcuts-extension': ['@jupyterlab/application'],
72 '@jupyterlab/tabmanager-extension': ['@jupyterlab/application'],
73 '@jupyterlab/theme-dark-extension': [
74 '@jupyterlab/application',
75 '@jupyterlab/apputils'
76 ],
77 '@jupyterlab/theme-light-extension': [
78 '@jupyterlab/application',
79 '@jupyterlab/apputils'
80 ],
81 '@jupyterlab/ui-extension': ['@blueprintjs/icons']
82};
83const pkgData = {};
84const pkgPaths = {};
85const pkgNames = {};
86const depCache = {};
87const locals = {};
88/**
89 * Ensure the metapackage package.
90 *
91 * @returns An array of messages for changes.
92 */
93function ensureMetaPackage() {
94 const basePath = path.resolve('.');
95 const mpPath = path.join(basePath, 'packages', 'metapackage');
96 const mpJson = path.join(mpPath, 'package.json');
97 const mpData = utils.readJSONFile(mpJson);
98 const messages = [];
99 const seen = {};
100 utils.getCorePaths().forEach(pkgPath => {
101 if (path.resolve(pkgPath) === path.resolve(mpPath)) {
102 return;
103 }
104 const name = pkgNames[pkgPath];
105 if (!name) {
106 return;
107 }
108 seen[name] = true;
109 const data = pkgData[name];
110 let valid = true;
111 // Ensure it is a dependency.
112 if (!mpData.dependencies[name]) {
113 valid = false;
114 mpData.dependencies[name] = '^' + data.version;
115 }
116 if (!valid) {
117 messages.push(`Updated: ${name}`);
118 }
119 });
120 // Make sure there are no extra deps.
121 Object.keys(mpData.dependencies).forEach(name => {
122 if (!(name in seen)) {
123 messages.push(`Removing dependency: ${name}`);
124 delete mpData.dependencies[name];
125 }
126 });
127 // Write the files.
128 if (messages.length > 0) {
129 utils.writePackageData(mpJson, mpData);
130 }
131 // Update the global data.
132 pkgData[mpData.name] = mpData;
133 return messages;
134}
135/**
136 * Ensure the jupyterlab application package.
137 */
138function ensureJupyterlab() {
139 const basePath = path.resolve('.');
140 const corePath = path.join(basePath, 'dev_mode', 'package.json');
141 const corePackage = utils.readJSONFile(corePath);
142 corePackage.jupyterlab.extensions = {};
143 corePackage.jupyterlab.mimeExtensions = {};
144 corePackage.jupyterlab.linkedPackages = {};
145 // start with known external dependencies
146 corePackage.dependencies = Object.assign({}, corePackage.jupyterlab.externalExtensions);
147 corePackage.resolutions = {};
148 const singletonPackages = corePackage.jupyterlab.singletonPackages;
149 const coreData = new Map();
150 utils.getCorePaths().forEach(pkgPath => {
151 const dataPath = path.join(pkgPath, 'package.json');
152 let data;
153 try {
154 data = utils.readJSONFile(dataPath);
155 }
156 catch (e) {
157 return;
158 }
159 coreData.set(data.name, data);
160 });
161 // Populate the yarn resolutions. First we make sure direct packages have
162 // resolutions.
163 coreData.forEach((data, name) => {
164 // Insist on a restricted version in the yarn resolution.
165 corePackage.resolutions[name] = `~${data.version}`;
166 });
167 // Then fill in any missing packages that should be singletons from the direct
168 // package dependencies.
169 coreData.forEach(data => {
170 if (data.dependencies) {
171 Object.entries(data.dependencies).forEach(([dep, version]) => {
172 if (singletonPackages.includes(dep) &&
173 !(dep in corePackage.resolutions)) {
174 corePackage.resolutions[dep] = version;
175 }
176 });
177 }
178 });
179 // At this point, each singleton should have a resolution. Check this.
180 const unresolvedSingletons = singletonPackages.filter(pkg => !(pkg in corePackage.resolutions));
181 if (unresolvedSingletons.length > 0) {
182 throw new Error(`Singleton packages must have a resolved version number; these do not: ${unresolvedSingletons.join(', ')}`);
183 }
184 coreData.forEach((data, name) => {
185 // Determine if the package wishes to be included in the top-level
186 // dependencies.
187 const meta = data.jupyterlab;
188 const keep = !!(meta &&
189 (meta.coreDependency || meta.extension || meta.mimeExtension));
190 if (!keep) {
191 return;
192 }
193 // Make sure it is included as a dependency.
194 corePackage.dependencies[data.name] = `~${data.version}`;
195 // Handle extensions.
196 ['extension', 'mimeExtension'].forEach(item => {
197 let ext = meta[item];
198 if (ext === true) {
199 ext = '';
200 }
201 if (typeof ext !== 'string') {
202 return;
203 }
204 corePackage.jupyterlab[`${item}s`][name] = ext;
205 });
206 });
207 utils.getLernaPaths().forEach(pkgPath => {
208 const dataPath = path.join(pkgPath, 'package.json');
209 let data;
210 try {
211 data = utils.readJSONFile(dataPath);
212 }
213 catch (e) {
214 return;
215 }
216 // Skip private packages.
217 if (data.private === true) {
218 return;
219 }
220 // watch all src, build, and test files in the Jupyterlab project
221 const relativePath = utils.ensureUnixPathSep(path.join('..', path.relative(basePath, pkgPath)));
222 corePackage.jupyterlab.linkedPackages[data.name] = relativePath;
223 });
224 // Write the package.json back to disk.
225 if (utils.writePackageData(corePath, corePackage)) {
226 return ['Updated dev mode'];
227 }
228 return [];
229}
230/**
231 * Ensure the repo integrity.
232 */
233async function ensureIntegrity() {
234 const messages = {};
235 // Pick up all the package versions.
236 const paths = utils.getLernaPaths();
237 // These two are not part of the workspaces but should be kept
238 // in sync.
239 paths.push('./jupyterlab/tests/mock_packages/extension');
240 paths.push('./jupyterlab/tests/mock_packages/mimeextension');
241 const cssImports = {};
242 // Get the package graph.
243 const graph = utils.getPackageGraph();
244 // Gather all of our package data and other metadata.
245 paths.forEach(pkgPath => {
246 // Read in the package.json.
247 let data;
248 try {
249 data = utils.readJSONFile(path.join(pkgPath, 'package.json'));
250 }
251 catch (e) {
252 console.error(e);
253 return;
254 }
255 pkgData[data.name] = data;
256 pkgPaths[data.name] = pkgPath;
257 pkgNames[pkgPath] = data.name;
258 locals[data.name] = pkgPath;
259 });
260 // Build up an ordered list of CSS imports for each local package.
261 Object.keys(locals).forEach(name => {
262 const data = pkgData[name];
263 const deps = data.dependencies || {};
264 const skip = SKIP_CSS[name] || [];
265 const cssData = {};
266 if (data.jupyterlab && data.jupyterlab.extraStyles) {
267 Object.keys(data.jupyterlab.extraStyles).forEach(depName => {
268 cssData[depName] = data.jupyterlab.extraStyles[depName];
269 });
270 }
271 Object.keys(deps).forEach(depName => {
272 // Bail for skipped imports and known extra styles.
273 if (skip.indexOf(depName) !== -1 || depName in cssData) {
274 return;
275 }
276 const depData = graph.getNodeData(depName);
277 if (typeof depData.style === 'string') {
278 cssData[depName] = [depData.style];
279 }
280 });
281 // Get our CSS imports in dependency order.
282 cssImports[name] = [];
283 graph.dependenciesOf(name).forEach(depName => {
284 if (depName in cssData) {
285 cssData[depName].forEach(cssPath => {
286 cssImports[name].push(`${depName}/${cssPath}`);
287 });
288 }
289 });
290 });
291 // Update the metapackage.
292 let pkgMessages = ensureMetaPackage();
293 if (pkgMessages.length > 0) {
294 const pkgName = '@jupyterlab/metapackage';
295 if (!messages[pkgName]) {
296 messages[pkgName] = [];
297 }
298 messages[pkgName] = messages[pkgName].concat(pkgMessages);
299 }
300 // Validate each package.
301 for (const name in locals) {
302 // application-top is handled elsewhere
303 if (name === '@jupyterlab/application-top') {
304 continue;
305 }
306 const unused = UNUSED[name] || [];
307 // Allow jest-junit to be unused in the test suite.
308 if (name.indexOf('@jupyterlab/test-') === 0) {
309 unused.push('jest-junit');
310 }
311 const options = {
312 pkgPath: pkgPaths[name],
313 data: pkgData[name],
314 depCache,
315 missing: MISSING[name],
316 unused,
317 locals,
318 cssImports: cssImports[name],
319 differentVersions: DIFFERENT_VERSIONS
320 };
321 if (name === '@jupyterlab/metapackage') {
322 options.noUnused = false;
323 }
324 const pkgMessages = await ensure_package_1.ensurePackage(options);
325 if (pkgMessages.length > 0) {
326 messages[name] = pkgMessages;
327 }
328 }
329 // ensure the icon svg imports
330 pkgMessages = await ensure_package_1.ensureUiComponents(pkgPaths['@jupyterlab/ui-components']);
331 if (pkgMessages.length > 0) {
332 const pkgName = '@jupyterlab/ui-components';
333 if (!messages[pkgName]) {
334 messages[pkgName] = [];
335 }
336 messages[pkgName] = messages[pkgName].concat(pkgMessages);
337 }
338 // Handle the top level package.
339 const corePath = path.resolve('.', 'package.json');
340 const coreData = utils.readJSONFile(corePath);
341 if (utils.writePackageData(corePath, coreData)) {
342 messages['top'] = ['Update package.json'];
343 }
344 // Handle the refs in the top level tsconfigdoc.json
345 const tsConfigdocPath = path.resolve('.', 'tsconfigdoc.json');
346 const tsConfigdocData = utils.readJSONFile(tsConfigdocPath);
347 tsConfigdocData.references = [];
348 utils.getCorePaths().forEach(pth => {
349 tsConfigdocData.references.push({ path: './' + path.relative('.', pth) });
350 });
351 utils.writeJSONFile(tsConfigdocPath, tsConfigdocData);
352 // Handle the JupyterLab application top package.
353 pkgMessages = ensureJupyterlab();
354 if (pkgMessages.length > 0) {
355 messages['@application/top'] = pkgMessages;
356 }
357 // Handle any messages.
358 if (Object.keys(messages).length > 0) {
359 console.debug(JSON.stringify(messages, null, 2));
360 if (process.argv.indexOf('--force') !== -1) {
361 console.debug('\n\nPlease run `jlpm run integrity` locally and commit the changes');
362 process.exit(1);
363 }
364 utils.run('jlpm install');
365 console.debug('\n\nMade integrity changes!');
366 console.debug('Please commit the changes by running:');
367 console.debug('git commit -a -m "Package integrity updates"');
368 return false;
369 }
370 console.debug('Repo integrity verified!');
371 return true;
372}
373exports.ensureIntegrity = ensureIntegrity;
374if (require.main === module) {
375 void ensureIntegrity();
376}
377//# sourceMappingURL=ensure-repo.js.map
\No newline at end of file