@unisphere/nx 3.2.3 → 3.2.4
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/dist/generators/add-application/add-application.d.ts.map +1 -1
- package/dist/generators/add-application/add-application.js +116 -10
- package/dist/generators/add-application/schema.d.ts +1 -1
- package/dist/generators/add-application/schema.json +4 -0
- package/dist/generators/internal-dev-runner/generator.d.ts.map +1 -1
- package/dist/generators/internal-dev-runner/generator.js +4 -2
- package/dist/migrations/3-1-0/fix-workspaces-pattern.d.ts +23 -0
- package/dist/migrations/3-1-0/fix-workspaces-pattern.d.ts.map +1 -0
- package/dist/migrations/3-1-0/fix-workspaces-pattern.js +72 -0
- package/migrations.json +9 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"add-application.d.ts","sourceRoot":"","sources":["../../../src/generators/add-application/add-application.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,IAAI,EAAsC,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"add-application.d.ts","sourceRoot":"","sources":["../../../src/generators/add-application/add-application.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,IAAI,EAAsC,MAAM,YAAY,CAAC;AAIlG,OAAO,EAAE,6BAA6B,EAAE,MAAM,UAAU,CAAC;AAkHzD,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,6BAA6B,uBAgQvC;AAED,eAAe,uBAAuB,CAAC"}
|
|
@@ -4,6 +4,8 @@ exports.addApplicationGenerator = addApplicationGenerator;
|
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const devkit_1 = require("@nx/devkit");
|
|
6
6
|
const path = tslib_1.__importStar(require("path"));
|
|
7
|
+
const child_process_1 = require("child_process");
|
|
8
|
+
const fs = tslib_1.__importStar(require("fs"));
|
|
7
9
|
const utils_1 = require("../utils");
|
|
8
10
|
const dependency_config_1 = require("../dependency-config");
|
|
9
11
|
async function getEnquirerPrompt() {
|
|
@@ -79,17 +81,50 @@ async function addApplicationGenerator(tree, options) {
|
|
|
79
81
|
throw new Error('iframe-with-post-messages serving type is not currently supported. Please choose a different serving type.');
|
|
80
82
|
}
|
|
81
83
|
const isPlayground = options.servingType === 'local-dev-playground';
|
|
84
|
+
const isDocumentation = options.servingType === 'documentation';
|
|
85
|
+
// Check workspace pattern for documentation apps
|
|
86
|
+
if (isDocumentation) {
|
|
87
|
+
const rootPackageJsonPath = 'package.json';
|
|
88
|
+
if (tree.exists(rootPackageJsonPath)) {
|
|
89
|
+
const packageJson = JSON.parse(tree.read(rootPackageJsonPath, 'utf-8') || '{}');
|
|
90
|
+
const workspaces = packageJson.workspaces || [];
|
|
91
|
+
// Check if using the old catch-all pattern that doesn't work with documentation apps
|
|
92
|
+
const hasCatchAllPattern = workspaces.includes('unisphere/**');
|
|
93
|
+
const hasNegationPattern = workspaces.some((pattern) => pattern.startsWith('!'));
|
|
94
|
+
if (hasCatchAllPattern || hasNegationPattern) {
|
|
95
|
+
throw new Error('Documentation applications require @unisphere/nx version 3.1.0 or higher.\n\n' +
|
|
96
|
+
'Your workspace is using an old npm workspaces pattern that prevents documentation apps ' +
|
|
97
|
+
'from having their own node_modules.\n\n' +
|
|
98
|
+
'Please upgrade by running:\n' +
|
|
99
|
+
' npx nx migrate @unisphere/nx@latest\n' +
|
|
100
|
+
' npx nx migrate --run-migrations\n\n' +
|
|
101
|
+
'This will update your workspace pattern to support documentation apps.');
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
82
105
|
// Validate and read .unisphere configuration
|
|
83
106
|
const unisphereConfig = (0, utils_1.validateUnisphereConfig)(tree);
|
|
84
|
-
|
|
85
|
-
|
|
107
|
+
// Skip runtime/visual prompts for documentation sites
|
|
108
|
+
let runtimeName = '';
|
|
109
|
+
let visualName = '';
|
|
110
|
+
if (!isDocumentation) {
|
|
111
|
+
const promptResult = await promptForRuntimeName(unisphereConfig.runtimes, options.runtimeName || '', options.visualName || '', options.skipDynamicRuntimeVisualPrompt || false);
|
|
112
|
+
runtimeName = promptResult.runtimeName;
|
|
113
|
+
visualName = promptResult.visualName;
|
|
114
|
+
}
|
|
115
|
+
// Skip HTML page title prompt for documentation (Docusaurus has its own config)
|
|
116
|
+
if (!isPlayground && !isDocumentation && !options.htmlPageTitle) {
|
|
86
117
|
options.htmlPageTitle = options.htmlPageTitle || await promptForHtmlPageTitle();
|
|
87
118
|
}
|
|
88
|
-
|
|
89
|
-
|
|
119
|
+
// Skip dependencies prompt for documentation (Docusaurus has its own)
|
|
120
|
+
let selectedDependencies = [];
|
|
121
|
+
if (!isDocumentation) {
|
|
122
|
+
if (options.dependencies === undefined) {
|
|
123
|
+
options.dependencies = await promptForDependencies(isPlayground);
|
|
124
|
+
}
|
|
125
|
+
const baseDependencies = ['react'];
|
|
126
|
+
selectedDependencies = [...baseDependencies, ...(options.dependencies || [])];
|
|
90
127
|
}
|
|
91
|
-
const baseDependencies = ['react'];
|
|
92
|
-
const selectedDependencies = [...baseDependencies, ...(options.dependencies || [])];
|
|
93
128
|
// Validate runtime exists if runtimeName is provided
|
|
94
129
|
if (runtimeName) {
|
|
95
130
|
if (!(0, utils_1.checkIfRuntimeExists)(tree, runtimeName)) {
|
|
@@ -103,12 +138,83 @@ async function addApplicationGenerator(tree, options) {
|
|
|
103
138
|
applicationName += '-dev';
|
|
104
139
|
}
|
|
105
140
|
const applicationNameAsLowerDashCase = (0, devkit_1.names)(applicationName).fileName;
|
|
106
|
-
// Find types package (or fallback to core)
|
|
107
|
-
const typesPackageInfo = (0, utils_1.findTypesOrCorePackageInfo)(tree);
|
|
141
|
+
// Find types package (or fallback to core) - skip for documentation
|
|
142
|
+
const typesPackageInfo = isDocumentation ? null : (0, utils_1.findTypesOrCorePackageInfo)(tree);
|
|
108
143
|
// Determine subdirectory based on serving type
|
|
109
|
-
// local-dev-playground -> local/, other types -> server/
|
|
110
|
-
const subdirectory = isPlayground ? 'local' : 'server';
|
|
144
|
+
// local-dev-playground -> local/, documentation -> documentation/, other types -> server/
|
|
145
|
+
const subdirectory = isPlayground ? 'local' : isDocumentation ? 'documentation' : 'server';
|
|
111
146
|
const projectRoot = `unisphere/applications/${subdirectory}/${applicationNameAsLowerDashCase}`;
|
|
147
|
+
// Handle documentation type separately
|
|
148
|
+
if (isDocumentation) {
|
|
149
|
+
// Check if the application already exists
|
|
150
|
+
if (tree.exists(projectRoot)) {
|
|
151
|
+
throw new Error(`Application "${applicationNameAsLowerDashCase}" already exists at ${projectRoot}.\n` +
|
|
152
|
+
'Please choose a different application name or remove the existing application first.');
|
|
153
|
+
}
|
|
154
|
+
// Update .unisphere configuration (applicationType is derived from folder path)
|
|
155
|
+
(0, utils_1.updateUnisphereConfig)(tree, 'applications', applicationNameAsLowerDashCase, {
|
|
156
|
+
sourceRoot: projectRoot,
|
|
157
|
+
});
|
|
158
|
+
// Add documentation folder to .nxignore to prevent NX from scanning it
|
|
159
|
+
// Docusaurus has its own node_modules which can slow down NX
|
|
160
|
+
const nxIgnorePath = '.nxignore';
|
|
161
|
+
const ignoreEntry = `${projectRoot}/node_modules`;
|
|
162
|
+
let nxIgnoreContent = '';
|
|
163
|
+
if (tree.exists(nxIgnorePath)) {
|
|
164
|
+
nxIgnoreContent = tree.read(nxIgnorePath, 'utf-8') || '';
|
|
165
|
+
}
|
|
166
|
+
if (!nxIgnoreContent.includes(ignoreEntry)) {
|
|
167
|
+
const newContent = nxIgnoreContent
|
|
168
|
+
? `${nxIgnoreContent.trimEnd()}\n\n# Documentation site (Docusaurus) - has its own node_modules\n${ignoreEntry}\n`
|
|
169
|
+
: `# Documentation site (Docusaurus) - has its own node_modules\n${ignoreEntry}\n`;
|
|
170
|
+
tree.write(nxIgnorePath, newContent);
|
|
171
|
+
}
|
|
172
|
+
// Documentation folders are automatically excluded from npm workspaces
|
|
173
|
+
// because the root package.json uses explicit workspace patterns that don't include
|
|
174
|
+
// unisphere/applications/documentation/**
|
|
175
|
+
// This allows documentation sites (like Docusaurus) to have their own node_modules
|
|
176
|
+
await (0, devkit_1.formatFiles)(tree);
|
|
177
|
+
// Return a function that will be executed after all file operations are complete
|
|
178
|
+
return () => {
|
|
179
|
+
const workspaceRoot = process.cwd();
|
|
180
|
+
const fullProjectPath = path.join(workspaceRoot, projectRoot);
|
|
181
|
+
devkit_1.logger.info('');
|
|
182
|
+
devkit_1.logger.info('📚 Setting up Docusaurus documentation site...');
|
|
183
|
+
devkit_1.logger.info('');
|
|
184
|
+
try {
|
|
185
|
+
// Create the parent directory if it doesn't exist
|
|
186
|
+
const parentDir = path.dirname(fullProjectPath);
|
|
187
|
+
if (!fs.existsSync(parentDir)) {
|
|
188
|
+
fs.mkdirSync(parentDir, { recursive: true });
|
|
189
|
+
}
|
|
190
|
+
// Run Docusaurus CLI to scaffold the project
|
|
191
|
+
// Docusaurus creates a self-contained project with its own package.json
|
|
192
|
+
// No NX integration needed - we just delegate to Docusaurus CLI for serve/build
|
|
193
|
+
// Use public npm registry explicitly (workspaces may have private registry configured)
|
|
194
|
+
devkit_1.logger.info('Running Docusaurus CLI...');
|
|
195
|
+
(0, child_process_1.execSync)(`npx --yes --registry https://registry.npmjs.org create-docusaurus@3 "${fullProjectPath}" classic --typescript`, {
|
|
196
|
+
stdio: 'inherit',
|
|
197
|
+
cwd: workspaceRoot,
|
|
198
|
+
});
|
|
199
|
+
devkit_1.logger.info('');
|
|
200
|
+
devkit_1.logger.info('✅ Documentation site generated successfully!');
|
|
201
|
+
devkit_1.logger.info('');
|
|
202
|
+
devkit_1.logger.info(`📚 Application Name: ${applicationNameAsLowerDashCase}`);
|
|
203
|
+
devkit_1.logger.info(`🔧 Type: Documentation Site (Docusaurus)`);
|
|
204
|
+
devkit_1.logger.info(`📁 Location: ${projectRoot}`);
|
|
205
|
+
devkit_1.logger.info('');
|
|
206
|
+
devkit_1.logger.info(`📜 To serve: npx unisphere application serve ${applicationNameAsLowerDashCase}`);
|
|
207
|
+
devkit_1.logger.info(`📦 To build: npx unisphere application build ${applicationNameAsLowerDashCase}`);
|
|
208
|
+
devkit_1.logger.info('');
|
|
209
|
+
}
|
|
210
|
+
catch (error) {
|
|
211
|
+
devkit_1.logger.error('Failed to create Docusaurus project:');
|
|
212
|
+
devkit_1.logger.error(error instanceof Error ? error.message : String(error));
|
|
213
|
+
throw error;
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
// Standard application flow (non-documentation)
|
|
112
218
|
const hasDs = selectedDependencies.includes('ds');
|
|
113
219
|
const templateVariables = {
|
|
114
220
|
htmlPageTitle: options.servingType === 'local-dev-playground'
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export interface AddApplicationGeneratorSchema {
|
|
2
2
|
name: string;
|
|
3
3
|
htmlPageTitle?: string;
|
|
4
|
-
servingType: 'local-dev-playground' | 'self-hosted' | 'iframe-with-post-messages';
|
|
4
|
+
servingType: 'local-dev-playground' | 'self-hosted' | 'iframe-with-post-messages' | 'documentation';
|
|
5
5
|
runtimeName?: string;
|
|
6
6
|
visualName?: string;
|
|
7
7
|
skipDynamicRuntimeVisualPrompt?: boolean; // Internal option to skip the dynamic prompt for visual when runtime is selected
|
|
@@ -33,6 +33,10 @@
|
|
|
33
33
|
{
|
|
34
34
|
"value": "iframe-with-post-messages",
|
|
35
35
|
"label": "Iframe + Post Messages (suitible to applications that gets required configuration from post messages)"
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"value": "documentation",
|
|
39
|
+
"label": "Documentation Site (Docusaurus)"
|
|
36
40
|
}
|
|
37
41
|
]
|
|
38
42
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../../src/generators/internal-dev-runner/generator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../../src/generators/internal-dev-runner/generator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAclC,wBAA8B,sBAAsB,CAAC,IAAI,EAAE,IAAI,iBAuC9D"}
|
|
@@ -11,7 +11,8 @@ const tslib_1 = require("tslib");
|
|
|
11
11
|
// import reorganizeApplicationsByDistributionChannel from '../../migrations/3-0-0/reorganize-applications-by-distribution-channel';
|
|
12
12
|
// import upgradeSchemaTo2 from '../../migrations/3-0-0/upgrade-schema-to-2-0-0';
|
|
13
13
|
// import postCleanupEmptyDirectories from '../../migrations/3-0-0/post-cleanup-empty-directories';
|
|
14
|
-
|
|
14
|
+
// import removePrivateFromApplicationsAndRuntimes from '../../migrations/3-0-0/remove-private-from-applications-and-runtimes';
|
|
15
|
+
const fix_workspaces_pattern_1 = tslib_1.__importDefault(require("../../migrations/3-1-0/fix-workspaces-pattern"));
|
|
15
16
|
async function testMigrationGenerator(tree) {
|
|
16
17
|
// Collect all callbacks to run after all migrations complete
|
|
17
18
|
// const callbacks: (() => void)[] = [];
|
|
@@ -29,7 +30,8 @@ async function testMigrationGenerator(tree) {
|
|
|
29
30
|
// Upgrade schema to 2.0.0 and remove distributionChannel from packages
|
|
30
31
|
// await upgradeSchemaTo2(tree);
|
|
31
32
|
// Remove private field from applications, runtimes, and packages
|
|
32
|
-
await (
|
|
33
|
+
// await removePrivateFromApplicationsAndRuntimes(tree);
|
|
34
|
+
await (0, fix_workspaces_pattern_1.default)(tree);
|
|
33
35
|
// Post-cleanup: Remove empty directories after reorganization
|
|
34
36
|
// const postCleanupCallback = await postCleanupEmptyDirectories(tree);
|
|
35
37
|
// if (postCleanupCallback) {
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Tree } from '@nx/devkit';
|
|
2
|
+
/**
|
|
3
|
+
* Migration: Fix npm workspaces pattern to use explicit includes
|
|
4
|
+
*
|
|
5
|
+
* This migration updates the root package.json workspaces array to use
|
|
6
|
+
* explicit include patterns instead of a catch-all pattern with exclusions.
|
|
7
|
+
*
|
|
8
|
+
* The problem with "unisphere/**" + "!unisphere/applications/documentation/**"
|
|
9
|
+
* is that npm's negation patterns don't work reliably. This caused documentation
|
|
10
|
+
* apps (like Docusaurus) to be unable to have their own node_modules.
|
|
11
|
+
*
|
|
12
|
+
* The fix is to use explicit patterns that only include what should be workspaces:
|
|
13
|
+
* - unisphere/packages/**
|
|
14
|
+
* - unisphere/runtimes/**
|
|
15
|
+
* - unisphere/visuals/**
|
|
16
|
+
* - unisphere/applications/local/**
|
|
17
|
+
* - unisphere/applications/server/**
|
|
18
|
+
*
|
|
19
|
+
* This automatically excludes unisphere/applications/documentation/** without
|
|
20
|
+
* needing a negation pattern.
|
|
21
|
+
*/
|
|
22
|
+
export default function update(tree: Tree): Promise<void>;
|
|
23
|
+
//# sourceMappingURL=fix-workspaces-pattern.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fix-workspaces-pattern.d.ts","sourceRoot":"","sources":["../../../src/migrations/3-1-0/fix-workspaces-pattern.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAA+B,MAAM,YAAY,CAAC;AAE/D;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAA8B,MAAM,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CA8D9D"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.default = update;
|
|
4
|
+
const devkit_1 = require("@nx/devkit");
|
|
5
|
+
/**
|
|
6
|
+
* Migration: Fix npm workspaces pattern to use explicit includes
|
|
7
|
+
*
|
|
8
|
+
* This migration updates the root package.json workspaces array to use
|
|
9
|
+
* explicit include patterns instead of a catch-all pattern with exclusions.
|
|
10
|
+
*
|
|
11
|
+
* The problem with "unisphere/**" + "!unisphere/applications/documentation/**"
|
|
12
|
+
* is that npm's negation patterns don't work reliably. This caused documentation
|
|
13
|
+
* apps (like Docusaurus) to be unable to have their own node_modules.
|
|
14
|
+
*
|
|
15
|
+
* The fix is to use explicit patterns that only include what should be workspaces:
|
|
16
|
+
* - unisphere/packages/**
|
|
17
|
+
* - unisphere/runtimes/**
|
|
18
|
+
* - unisphere/visuals/**
|
|
19
|
+
* - unisphere/applications/local/**
|
|
20
|
+
* - unisphere/applications/server/**
|
|
21
|
+
*
|
|
22
|
+
* This automatically excludes unisphere/applications/documentation/** without
|
|
23
|
+
* needing a negation pattern.
|
|
24
|
+
*/
|
|
25
|
+
async function update(tree) {
|
|
26
|
+
devkit_1.logger.info('🔄 Fixing npm workspaces pattern to use explicit includes');
|
|
27
|
+
const packageJsonPath = 'package.json';
|
|
28
|
+
if (!tree.exists(packageJsonPath)) {
|
|
29
|
+
devkit_1.logger.warn('No package.json found, skipping migration');
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
const packageJson = (0, devkit_1.readJson)(tree, packageJsonPath);
|
|
33
|
+
if (!packageJson.workspaces || !Array.isArray(packageJson.workspaces)) {
|
|
34
|
+
devkit_1.logger.warn('No workspaces array found in package.json, skipping migration');
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
const oldWorkspaces = packageJson.workspaces;
|
|
38
|
+
// Check if using the old catch-all pattern
|
|
39
|
+
const hasCatchAllPattern = oldWorkspaces.includes('unisphere/**');
|
|
40
|
+
const hasNegationPattern = oldWorkspaces.some((pattern) => pattern.startsWith('!'));
|
|
41
|
+
if (!hasCatchAllPattern && !hasNegationPattern) {
|
|
42
|
+
// Check if already using explicit patterns
|
|
43
|
+
const expectedPatterns = [
|
|
44
|
+
'unisphere/packages/**',
|
|
45
|
+
'unisphere/runtimes/**',
|
|
46
|
+
'unisphere/visuals/**',
|
|
47
|
+
'unisphere/applications/local/**',
|
|
48
|
+
'unisphere/applications/server/**',
|
|
49
|
+
];
|
|
50
|
+
const hasAllExpectedPatterns = expectedPatterns.every(pattern => oldWorkspaces.includes(pattern));
|
|
51
|
+
if (hasAllExpectedPatterns) {
|
|
52
|
+
devkit_1.logger.info('Workspaces already using explicit patterns, skipping migration');
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
// Replace with explicit patterns
|
|
57
|
+
const newWorkspaces = [
|
|
58
|
+
'unisphere/packages/**',
|
|
59
|
+
'unisphere/runtimes/**',
|
|
60
|
+
'unisphere/visuals/**',
|
|
61
|
+
'unisphere/applications/local/**',
|
|
62
|
+
'unisphere/applications/server/**',
|
|
63
|
+
];
|
|
64
|
+
packageJson.workspaces = newWorkspaces;
|
|
65
|
+
(0, devkit_1.writeJson)(tree, packageJsonPath, packageJson);
|
|
66
|
+
devkit_1.logger.info('✅ Updated workspaces from:');
|
|
67
|
+
devkit_1.logger.info(` ${JSON.stringify(oldWorkspaces)}`);
|
|
68
|
+
devkit_1.logger.info(' to:');
|
|
69
|
+
devkit_1.logger.info(` ${JSON.stringify(newWorkspaces)}`);
|
|
70
|
+
devkit_1.logger.info('');
|
|
71
|
+
devkit_1.logger.info('This allows documentation apps (like Docusaurus) to have their own node_modules.');
|
|
72
|
+
}
|
package/migrations.json
CHANGED
|
@@ -273,7 +273,15 @@
|
|
|
273
273
|
"3-0-0-remove-pre-install": {
|
|
274
274
|
"version": "3.0.0",
|
|
275
275
|
"description": "Removes kaltura-tools preinstall script from package.json",
|
|
276
|
-
"factory": "./dist/migrations/3-0-0/remove-kaltura-tools-to-pre-install.js"
|
|
276
|
+
"factory": "./dist/migrations/3-0-0/remove-kaltura-tools-to-pre-install.js"
|
|
277
|
+
},
|
|
278
|
+
"3-1-0-fix-workspaces-pattern": {
|
|
279
|
+
"version": "3.1.0",
|
|
280
|
+
"description": "Fixes npm workspaces pattern to use explicit includes instead of catch-all with exclusions",
|
|
281
|
+
"factory": "./dist/migrations/3-1-0/fix-workspaces-pattern.js",
|
|
282
|
+
"cli": {
|
|
283
|
+
"postUpdateMessage": "✅ npm workspaces pattern updated to use explicit includes. Documentation apps can now have their own node_modules."
|
|
284
|
+
}
|
|
277
285
|
}
|
|
278
286
|
},
|
|
279
287
|
"packageJsonUpdates": {
|