@commercetools-frontend/create-mc-app 27.6.2 → 27.6.3
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/CHANGELOG.md +22 -0
- package/dist/commercetools-frontend-create-mc-app.cjs.dev.js +150 -54
- package/dist/commercetools-frontend-create-mc-app.cjs.prod.js +150 -54
- package/dist/commercetools-frontend-create-mc-app.esm.js +147 -50
- package/package.json +4 -3
- package/src/process-options.ts +20 -0
- package/src/tasks/download-template.ts +4 -13
- package/src/tasks/update-package-json.ts +165 -42
- package/src/types.ts +4 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# @commercetools-frontend/create-mc-app
|
|
2
2
|
|
|
3
|
+
## 27.6.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#4019](https://github.com/commercetools/merchant-center-application-kit/pull/4019) [`2bf3322`](https://github.com/commercetools/merchant-center-application-kit/commit/2bf33221525be981c8a03a951bfb6387438624a6) Thanks [@misama-ct](https://github.com/misama-ct)! - Support `workspace:^` and `catalog:` specifiers when scaffolding —
|
|
8
|
+
previously the CLI only handled `workspace:*`, so apps generated from
|
|
9
|
+
the latest templates failed to install.
|
|
10
|
+
|
|
11
|
+
Scaffolded `package.json` files now pin internal
|
|
12
|
+
`@commercetools-frontend/*` deps with caret ranges (`^x.y.z`) instead
|
|
13
|
+
of exact versions. Application Kit packages release in lockstep, so a
|
|
14
|
+
caret range always resolves to a synchronized set of latest patches —
|
|
15
|
+
the lockstep invariant is preserved, and subsequent
|
|
16
|
+
`npm install` / `yarn install` / `pnpm install` runs pick up
|
|
17
|
+
patch/minor updates automatically.
|
|
18
|
+
|
|
19
|
+
`npx create-mc-app …` continues to work against any template version,
|
|
20
|
+
old or new.
|
|
21
|
+
|
|
22
|
+
- Updated dependencies []:
|
|
23
|
+
- @commercetools-frontend/application-config@27.6.3
|
|
24
|
+
|
|
3
25
|
## 27.6.2
|
|
4
26
|
|
|
5
27
|
### Patch Changes
|
|
@@ -9,7 +9,9 @@ var execa = require('execa');
|
|
|
9
9
|
var semver = require('semver');
|
|
10
10
|
var _Promise = require('@babel/runtime-corejs3/core-js-stable/promise');
|
|
11
11
|
var _startsWithInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/starts-with');
|
|
12
|
+
var _Date$now = require('@babel/runtime-corejs3/core-js-stable/date/now');
|
|
12
13
|
var crypto = require('node:crypto');
|
|
14
|
+
var os = require('node:os');
|
|
13
15
|
var path = require('node:path');
|
|
14
16
|
var readline = require('node:readline');
|
|
15
17
|
var applicationConfig = require('@commercetools-frontend/application-config');
|
|
@@ -21,8 +23,6 @@ var fs = require('node:fs');
|
|
|
21
23
|
var _Object$keys = require('@babel/runtime-corejs3/core-js-stable/object/keys');
|
|
22
24
|
var _includesInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/includes');
|
|
23
25
|
var _Object$values = require('@babel/runtime-corejs3/core-js-stable/object/values');
|
|
24
|
-
var _Date$now = require('@babel/runtime-corejs3/core-js-stable/date/now');
|
|
25
|
-
var os = require('node:os');
|
|
26
26
|
var _Object$getOwnPropertySymbols = require('@babel/runtime-corejs3/core-js-stable/object/get-own-property-symbols');
|
|
27
27
|
var _Object$getOwnPropertyDescriptor = require('@babel/runtime-corejs3/core-js-stable/object/get-own-property-descriptor');
|
|
28
28
|
var _forEachInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/for-each');
|
|
@@ -31,10 +31,10 @@ var _Object$defineProperties = require('@babel/runtime-corejs3/core-js-stable/ob
|
|
|
31
31
|
var _Object$defineProperty = require('@babel/runtime-corejs3/core-js-stable/object/define-property');
|
|
32
32
|
var _defineProperty = require('@babel/runtime-corejs3/helpers/defineProperty');
|
|
33
33
|
var _slicedToArray = require('@babel/runtime-corejs3/helpers/slicedToArray');
|
|
34
|
-
var
|
|
34
|
+
var _Map = require('@babel/runtime-corejs3/core-js-stable/map');
|
|
35
35
|
var _Object$entries = require('@babel/runtime-corejs3/core-js-stable/object/entries');
|
|
36
|
-
var _Object$assign = require('@babel/runtime-corejs3/core-js-stable/object/assign');
|
|
37
36
|
var _JSON$stringify = require('@babel/runtime-corejs3/core-js-stable/json/stringify');
|
|
37
|
+
var yaml = require('yaml');
|
|
38
38
|
var core = require('@babel/core');
|
|
39
39
|
var prettier = require('prettier');
|
|
40
40
|
|
|
@@ -45,7 +45,9 @@ var execa__default = /*#__PURE__*/_interopDefault(execa);
|
|
|
45
45
|
var semver__default = /*#__PURE__*/_interopDefault(semver);
|
|
46
46
|
var _Promise__default = /*#__PURE__*/_interopDefault(_Promise);
|
|
47
47
|
var _startsWithInstanceProperty__default = /*#__PURE__*/_interopDefault(_startsWithInstanceProperty);
|
|
48
|
+
var _Date$now__default = /*#__PURE__*/_interopDefault(_Date$now);
|
|
48
49
|
var crypto__default = /*#__PURE__*/_interopDefault(crypto);
|
|
50
|
+
var os__default = /*#__PURE__*/_interopDefault(os);
|
|
49
51
|
var path__default = /*#__PURE__*/_interopDefault(path);
|
|
50
52
|
var readline__default = /*#__PURE__*/_interopDefault(readline);
|
|
51
53
|
var _trimInstanceProperty__default = /*#__PURE__*/_interopDefault(_trimInstanceProperty);
|
|
@@ -56,23 +58,20 @@ var fs__default = /*#__PURE__*/_interopDefault(fs);
|
|
|
56
58
|
var _Object$keys__default = /*#__PURE__*/_interopDefault(_Object$keys);
|
|
57
59
|
var _includesInstanceProperty__default = /*#__PURE__*/_interopDefault(_includesInstanceProperty);
|
|
58
60
|
var _Object$values__default = /*#__PURE__*/_interopDefault(_Object$values);
|
|
59
|
-
var _Date$now__default = /*#__PURE__*/_interopDefault(_Date$now);
|
|
60
|
-
var os__default = /*#__PURE__*/_interopDefault(os);
|
|
61
61
|
var _Object$getOwnPropertySymbols__default = /*#__PURE__*/_interopDefault(_Object$getOwnPropertySymbols);
|
|
62
62
|
var _Object$getOwnPropertyDescriptor__default = /*#__PURE__*/_interopDefault(_Object$getOwnPropertyDescriptor);
|
|
63
63
|
var _forEachInstanceProperty__default = /*#__PURE__*/_interopDefault(_forEachInstanceProperty);
|
|
64
64
|
var _Object$getOwnPropertyDescriptors__default = /*#__PURE__*/_interopDefault(_Object$getOwnPropertyDescriptors);
|
|
65
65
|
var _Object$defineProperties__default = /*#__PURE__*/_interopDefault(_Object$defineProperties);
|
|
66
66
|
var _Object$defineProperty__default = /*#__PURE__*/_interopDefault(_Object$defineProperty);
|
|
67
|
-
var
|
|
67
|
+
var _Map__default = /*#__PURE__*/_interopDefault(_Map);
|
|
68
68
|
var _Object$entries__default = /*#__PURE__*/_interopDefault(_Object$entries);
|
|
69
|
-
var _Object$assign__default = /*#__PURE__*/_interopDefault(_Object$assign);
|
|
70
69
|
var _JSON$stringify__default = /*#__PURE__*/_interopDefault(_JSON$stringify);
|
|
71
70
|
var prettier__default = /*#__PURE__*/_interopDefault(prettier);
|
|
72
71
|
|
|
73
72
|
var pkgJson = {
|
|
74
73
|
name: "@commercetools-frontend/create-mc-app",
|
|
75
|
-
version: "27.6.
|
|
74
|
+
version: "27.6.3",
|
|
76
75
|
description: "Create Merchant Center applications to quickly get up and running",
|
|
77
76
|
bugs: "https://github.com/commercetools/merchant-center-application-kit/issues",
|
|
78
77
|
repository: {
|
|
@@ -95,21 +94,22 @@ var pkgJson = {
|
|
|
95
94
|
module: "dist/commercetools-frontend-create-mc-app.esm.js",
|
|
96
95
|
bin: "./bin/cli.js",
|
|
97
96
|
dependencies: {
|
|
98
|
-
"@babel/core": "
|
|
99
|
-
"@babel/runtime": "
|
|
100
|
-
"@babel/runtime-corejs3": "
|
|
101
|
-
"@commercetools-frontend/application-config": "
|
|
102
|
-
"@types/babel__core": "
|
|
103
|
-
"@types/semver": "
|
|
104
|
-
commander: "
|
|
105
|
-
execa: "
|
|
106
|
-
listr2: "
|
|
107
|
-
prettier: "
|
|
108
|
-
semver: "
|
|
97
|
+
"@babel/core": "catalog:build",
|
|
98
|
+
"@babel/runtime": "catalog:build",
|
|
99
|
+
"@babel/runtime-corejs3": "catalog:build",
|
|
100
|
+
"@commercetools-frontend/application-config": "workspace:^",
|
|
101
|
+
"@types/babel__core": "catalog:",
|
|
102
|
+
"@types/semver": "catalog:",
|
|
103
|
+
commander: "catalog:",
|
|
104
|
+
execa: "catalog:",
|
|
105
|
+
listr2: "catalog:",
|
|
106
|
+
prettier: "catalog:lint",
|
|
107
|
+
semver: "catalog:",
|
|
108
|
+
yaml: "catalog:"
|
|
109
109
|
},
|
|
110
110
|
devDependencies: {
|
|
111
|
-
"@tsconfig/node22": "
|
|
112
|
-
"@types/prettier": "
|
|
111
|
+
"@tsconfig/node22": "catalog:",
|
|
112
|
+
"@types/prettier": "catalog:"
|
|
113
113
|
},
|
|
114
114
|
engines: {
|
|
115
115
|
node: "18.x || 20.x || >=22.0.0"
|
|
@@ -345,12 +345,22 @@ async function processOptions(projectDirectoryName, options) {
|
|
|
345
345
|
const initialProjectKey = await getInitialProjectKey(rl, options);
|
|
346
346
|
const cloudIdentifier = await getCloudIdentifier(rl, options);
|
|
347
347
|
rl.close();
|
|
348
|
+
|
|
349
|
+
// Compute the path used by `downloadTemplate` to clone the app-kit repo
|
|
350
|
+
// here so subsequent tasks (e.g. `updatePackageJson`) can read
|
|
351
|
+
// pnpm-workspace.yaml from the same checkout to resolve catalog refs.
|
|
352
|
+
// Branch names with `/` (`feat/foo`) would otherwise create a nested
|
|
353
|
+
// tmp path and break dirname/basename splits downstream — sanitize them
|
|
354
|
+
// into the folder name only.
|
|
355
|
+
const safeBranchSegment = tagOrBranchVersion.replace(/[^A-Za-z0-9._-]/g, '_');
|
|
356
|
+
const clonedRepositoryPath = path__default["default"].join(os__default["default"].tmpdir(), ['merchant-center-application-kit', '--', safeBranchSegment, '--', _Date$now__default["default"]().toString()].join(''));
|
|
348
357
|
return {
|
|
349
358
|
applicationType: options.applicationType,
|
|
350
359
|
projectDirectoryName,
|
|
351
360
|
projectDirectoryPath,
|
|
352
361
|
templateName,
|
|
353
362
|
tagOrBranchVersion,
|
|
363
|
+
clonedRepositoryPath,
|
|
354
364
|
entryPointUriPath,
|
|
355
365
|
initialProjectKey,
|
|
356
366
|
cloudIdentifier,
|
|
@@ -363,9 +373,9 @@ function downloadTemplate(options) {
|
|
|
363
373
|
return {
|
|
364
374
|
title: 'Downloading template',
|
|
365
375
|
task: () => {
|
|
366
|
-
const
|
|
367
|
-
const
|
|
368
|
-
const
|
|
376
|
+
const clonedRepositoryPath = options.clonedRepositoryPath;
|
|
377
|
+
const tmpDir = path__default["default"].dirname(clonedRepositoryPath);
|
|
378
|
+
const tmpFolderNameForClonedRepository = path__default["default"].basename(clonedRepositoryPath);
|
|
369
379
|
const templateFolderPath = path__default["default"].join(clonedRepositoryPath, options.applicationType === applicationTypes['custom-view'] ? 'custom-views-templates' : 'application-templates', options.templateName);
|
|
370
380
|
return new listr2.Listr([{
|
|
371
381
|
title: `Cloning repository using branch ${options.tagOrBranchVersion}`,
|
|
@@ -439,20 +449,120 @@ function installDependencies(options) {
|
|
|
439
449
|
}
|
|
440
450
|
|
|
441
451
|
function ownKeys(e, r) { var t = _Object$keys__default["default"](e); if (_Object$getOwnPropertySymbols__default["default"]) { var o = _Object$getOwnPropertySymbols__default["default"](e); r && (o = _filterInstanceProperty__default["default"](o).call(o, function (r) { return _Object$getOwnPropertyDescriptor__default["default"](e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
442
|
-
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
452
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var _context, _context2; var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? _forEachInstanceProperty__default["default"](_context = ownKeys(Object(t), !0)).call(_context, function (r) { _defineProperty(e, r, t[r]); }) : _Object$getOwnPropertyDescriptors__default["default"] ? _Object$defineProperties__default["default"](e, _Object$getOwnPropertyDescriptors__default["default"](t)) : _forEachInstanceProperty__default["default"](_context2 = ownKeys(Object(t))).call(_context2, function (r) { _Object$defineProperty__default["default"](e, r, _Object$getOwnPropertyDescriptor__default["default"](t, r)); }); } return e; }
|
|
453
|
+
|
|
454
|
+
// Catalog references in workspace package.json files point at entries in
|
|
455
|
+
// pnpm-workspace.yaml. They have to be flattened to concrete version
|
|
456
|
+
// specifiers in the scaffolded app because the scaffolded app is not part
|
|
457
|
+
// of any workspace.
|
|
458
|
+
//
|
|
459
|
+
// Shape: catalogName -> depName -> resolved spec. The default `catalog:`
|
|
460
|
+
// block is keyed as 'default' so `catalog:` and `catalog:<name>` lookups
|
|
461
|
+
// share one code path.
|
|
462
|
+
|
|
463
|
+
function parseCatalogs(yamlText) {
|
|
464
|
+
const doc = yaml.parse(yamlText) ?? {};
|
|
465
|
+
const out = new _Map__default["default"]();
|
|
466
|
+
if (doc.catalog) {
|
|
467
|
+
out.set('default', new _Map__default["default"](_Object$entries__default["default"](doc.catalog)));
|
|
468
|
+
}
|
|
469
|
+
for (const _ref of _Object$entries__default["default"](doc.catalogs ?? {})) {
|
|
470
|
+
var _ref2 = _slicedToArray(_ref, 2);
|
|
471
|
+
const name = _ref2[0];
|
|
472
|
+
const entries = _ref2[1];
|
|
473
|
+
out.set(name, new _Map__default["default"](_Object$entries__default["default"](entries)));
|
|
474
|
+
}
|
|
475
|
+
return out;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
// `workspace:` specifier → rewriter that takes the release version and
|
|
479
|
+
// returns the concrete spec. The supported set is data, not branching
|
|
480
|
+
// logic — extend the table to handle new protocol additions.
|
|
481
|
+
const WORKSPACE_REWRITERS = {
|
|
482
|
+
'workspace:*': v => v,
|
|
483
|
+
'workspace:^': v => `^${v}`,
|
|
484
|
+
'workspace:~': v => `~${v}`
|
|
455
485
|
};
|
|
486
|
+
|
|
487
|
+
/**
|
|
488
|
+
* Resolve a `catalog:` / `catalog:<name>` specifier to a concrete version
|
|
489
|
+
* string by looking it up in the parsed `pnpm-workspace.yaml`.
|
|
490
|
+
*
|
|
491
|
+
* @throws {Error} when the named catalog does not exist in the template's
|
|
492
|
+
* `pnpm-workspace.yaml`, or when the catalog exists but does not declare
|
|
493
|
+
* an entry for `depName`. Both cases mean the scaffold cannot produce a
|
|
494
|
+
* valid `package.json` and is unrecoverable — let it propagate.
|
|
495
|
+
*/
|
|
496
|
+
function resolveCatalogRef(spec, depName, catalogs) {
|
|
497
|
+
// `catalog:` and `catalog:default` both target the default block.
|
|
498
|
+
const name = spec === 'catalog:' || spec === 'catalog:default' ? 'default' : _sliceInstanceProperty__default["default"](spec).call(spec, 'catalog:'.length);
|
|
499
|
+
const block = catalogs.get(name);
|
|
500
|
+
if (!block) {
|
|
501
|
+
throw new Error(`Unable to resolve catalog reference "${spec}" for "${depName}": catalog "${name}" is not declared in the template's pnpm-workspace.yaml.`);
|
|
502
|
+
}
|
|
503
|
+
const resolved = block.get(depName);
|
|
504
|
+
if (!resolved) {
|
|
505
|
+
const where = name === 'default' ? 'the default catalog' : `catalogs.${name}`;
|
|
506
|
+
throw new Error(`Unable to resolve catalog reference "${spec}" for "${depName}": dep is not declared under ${where} in the template's pnpm-workspace.yaml.`);
|
|
507
|
+
}
|
|
508
|
+
return resolved;
|
|
509
|
+
}
|
|
510
|
+
function resolveSpec(depName, spec, releaseVersion, catalogs) {
|
|
511
|
+
const workspaceRewriter = WORKSPACE_REWRITERS[spec];
|
|
512
|
+
if (workspaceRewriter) return workspaceRewriter(releaseVersion);
|
|
513
|
+
if (_startsWithInstanceProperty__default["default"](spec).call(spec, 'catalog:')) return resolveCatalogRef(spec, depName, catalogs);
|
|
514
|
+
return spec;
|
|
515
|
+
}
|
|
516
|
+
function resolveDependencies() {
|
|
517
|
+
let dependencies = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
518
|
+
let releaseVersion = arguments.length > 1 ? arguments[1] : undefined;
|
|
519
|
+
let catalogs = arguments.length > 2 ? arguments[2] : undefined;
|
|
520
|
+
const out = {};
|
|
521
|
+
for (const _ref3 of _Object$entries__default["default"](dependencies)) {
|
|
522
|
+
var _ref4 = _slicedToArray(_ref3, 2);
|
|
523
|
+
const name = _ref4[0];
|
|
524
|
+
const spec = _ref4[1];
|
|
525
|
+
out[name] = resolveSpec(name, spec, releaseVersion, catalogs);
|
|
526
|
+
}
|
|
527
|
+
return out;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
// Read catalogs from the cloned template repo. Older template tags predate
|
|
531
|
+
// catalog adoption — fall back to an empty map so the workspace-only
|
|
532
|
+
// rewrite path still works.
|
|
533
|
+
function loadCatalogsFromClone(clonedRepositoryPath) {
|
|
534
|
+
const workspaceYamlPath = path__default["default"].join(clonedRepositoryPath, 'pnpm-workspace.yaml');
|
|
535
|
+
if (!fs__default["default"].existsSync(workspaceYamlPath)) return new _Map__default["default"]();
|
|
536
|
+
return parseCatalogs(fs__default["default"].readFileSync(workspaceYamlPath, {
|
|
537
|
+
encoding: 'utf8'
|
|
538
|
+
}));
|
|
539
|
+
}
|
|
540
|
+
function buildUpdatedPackageJson(appPackageJson, options, releaseVersion, catalogs) {
|
|
541
|
+
const packageManager = getPreferredPackageManager(options);
|
|
542
|
+
// Flatten workspace: and catalog: specifiers into concrete versions across
|
|
543
|
+
// every dependency section — the scaffolded app is not part of any pnpm
|
|
544
|
+
// workspace and would otherwise fail to install.
|
|
545
|
+
const resolve = deps => resolveDependencies(deps, releaseVersion, catalogs);
|
|
546
|
+
return _objectSpread(_objectSpread(_objectSpread(_objectSpread({}, appPackageJson), {}, {
|
|
547
|
+
version: '1.0.0',
|
|
548
|
+
// Given the package name is derived from the `projectDirectoryName`
|
|
549
|
+
// the latter needs to be sanitised to have a ensure a valid package name.
|
|
550
|
+
// The `projectDirectoryName` should not have restrictions (e.g. no `_`)
|
|
551
|
+
// as a result the package name potentially needs to be altered when derived.
|
|
552
|
+
name: slugify(options.projectDirectoryName),
|
|
553
|
+
description: '',
|
|
554
|
+
dependencies: resolve(appPackageJson.dependencies),
|
|
555
|
+
devDependencies: resolve(appPackageJson.devDependencies)
|
|
556
|
+
}, appPackageJson.peerDependencies && {
|
|
557
|
+
peerDependencies: resolve(appPackageJson.peerDependencies)
|
|
558
|
+
}), appPackageJson.optionalDependencies && {
|
|
559
|
+
optionalDependencies: resolve(appPackageJson.optionalDependencies)
|
|
560
|
+
}), {}, {
|
|
561
|
+
scripts: _objectSpread(_objectSpread({}, appPackageJson.scripts), {}, {
|
|
562
|
+
'start:prod:local': appPackageJson.scripts['start:prod:local'].replace('yarn', packageManager)
|
|
563
|
+
})
|
|
564
|
+
});
|
|
565
|
+
}
|
|
456
566
|
function updatePackageJson(options, releaseVersion) {
|
|
457
567
|
return {
|
|
458
568
|
title: 'Updating package.json',
|
|
@@ -461,22 +571,8 @@ function updatePackageJson(options, releaseVersion) {
|
|
|
461
571
|
const appPackageJson = JSON.parse(fs__default["default"].readFileSync(packageJsonPath, {
|
|
462
572
|
encoding: 'utf8'
|
|
463
573
|
}));
|
|
464
|
-
const
|
|
465
|
-
const updatedAppPackageJson =
|
|
466
|
-
version: '1.0.0',
|
|
467
|
-
// Given the package name is derived from the `projectDirectoryName`
|
|
468
|
-
// the latter needs to be sanitised to have a ensure a valid package name.
|
|
469
|
-
// The `projectDirectoryName` should not have restrictions (e.g. no `_`)
|
|
470
|
-
// as a result the package name potentially needs to be altered when derived.
|
|
471
|
-
name: slugify(options.projectDirectoryName),
|
|
472
|
-
description: '',
|
|
473
|
-
// Replace the package versions with the `workspace:` syntax to the real version.
|
|
474
|
-
dependencies: replaceApplicationKitPackageVersionWith(releaseVersion, appPackageJson.dependencies),
|
|
475
|
-
devDependencies: replaceApplicationKitPackageVersionWith(releaseVersion, appPackageJson.devDependencies),
|
|
476
|
-
scripts: _objectSpread(_objectSpread({}, appPackageJson.scripts), {}, {
|
|
477
|
-
'start:prod:local': appPackageJson.scripts['start:prod:local'].replace('yarn', packageManager)
|
|
478
|
-
})
|
|
479
|
-
});
|
|
574
|
+
const catalogs = loadCatalogsFromClone(options.clonedRepositoryPath);
|
|
575
|
+
const updatedAppPackageJson = buildUpdatedPackageJson(appPackageJson, options, releaseVersion, catalogs);
|
|
480
576
|
fs__default["default"].writeFileSync(packageJsonPath, _JSON$stringify__default["default"](updatedAppPackageJson, null, 2) + os__default["default"].EOL, {
|
|
481
577
|
encoding: 'utf8'
|
|
482
578
|
});
|
|
@@ -9,7 +9,9 @@ var execa = require('execa');
|
|
|
9
9
|
var semver = require('semver');
|
|
10
10
|
var _Promise = require('@babel/runtime-corejs3/core-js-stable/promise');
|
|
11
11
|
var _startsWithInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/starts-with');
|
|
12
|
+
var _Date$now = require('@babel/runtime-corejs3/core-js-stable/date/now');
|
|
12
13
|
var crypto = require('node:crypto');
|
|
14
|
+
var os = require('node:os');
|
|
13
15
|
var path = require('node:path');
|
|
14
16
|
var readline = require('node:readline');
|
|
15
17
|
var applicationConfig = require('@commercetools-frontend/application-config');
|
|
@@ -21,8 +23,6 @@ var fs = require('node:fs');
|
|
|
21
23
|
var _Object$keys = require('@babel/runtime-corejs3/core-js-stable/object/keys');
|
|
22
24
|
var _includesInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/includes');
|
|
23
25
|
var _Object$values = require('@babel/runtime-corejs3/core-js-stable/object/values');
|
|
24
|
-
var _Date$now = require('@babel/runtime-corejs3/core-js-stable/date/now');
|
|
25
|
-
var os = require('node:os');
|
|
26
26
|
var _Object$getOwnPropertySymbols = require('@babel/runtime-corejs3/core-js-stable/object/get-own-property-symbols');
|
|
27
27
|
var _Object$getOwnPropertyDescriptor = require('@babel/runtime-corejs3/core-js-stable/object/get-own-property-descriptor');
|
|
28
28
|
var _forEachInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/for-each');
|
|
@@ -31,10 +31,10 @@ var _Object$defineProperties = require('@babel/runtime-corejs3/core-js-stable/ob
|
|
|
31
31
|
var _Object$defineProperty = require('@babel/runtime-corejs3/core-js-stable/object/define-property');
|
|
32
32
|
var _defineProperty = require('@babel/runtime-corejs3/helpers/defineProperty');
|
|
33
33
|
var _slicedToArray = require('@babel/runtime-corejs3/helpers/slicedToArray');
|
|
34
|
-
var
|
|
34
|
+
var _Map = require('@babel/runtime-corejs3/core-js-stable/map');
|
|
35
35
|
var _Object$entries = require('@babel/runtime-corejs3/core-js-stable/object/entries');
|
|
36
|
-
var _Object$assign = require('@babel/runtime-corejs3/core-js-stable/object/assign');
|
|
37
36
|
var _JSON$stringify = require('@babel/runtime-corejs3/core-js-stable/json/stringify');
|
|
37
|
+
var yaml = require('yaml');
|
|
38
38
|
var core = require('@babel/core');
|
|
39
39
|
var prettier = require('prettier');
|
|
40
40
|
|
|
@@ -45,7 +45,9 @@ var execa__default = /*#__PURE__*/_interopDefault(execa);
|
|
|
45
45
|
var semver__default = /*#__PURE__*/_interopDefault(semver);
|
|
46
46
|
var _Promise__default = /*#__PURE__*/_interopDefault(_Promise);
|
|
47
47
|
var _startsWithInstanceProperty__default = /*#__PURE__*/_interopDefault(_startsWithInstanceProperty);
|
|
48
|
+
var _Date$now__default = /*#__PURE__*/_interopDefault(_Date$now);
|
|
48
49
|
var crypto__default = /*#__PURE__*/_interopDefault(crypto);
|
|
50
|
+
var os__default = /*#__PURE__*/_interopDefault(os);
|
|
49
51
|
var path__default = /*#__PURE__*/_interopDefault(path);
|
|
50
52
|
var readline__default = /*#__PURE__*/_interopDefault(readline);
|
|
51
53
|
var _trimInstanceProperty__default = /*#__PURE__*/_interopDefault(_trimInstanceProperty);
|
|
@@ -56,23 +58,20 @@ var fs__default = /*#__PURE__*/_interopDefault(fs);
|
|
|
56
58
|
var _Object$keys__default = /*#__PURE__*/_interopDefault(_Object$keys);
|
|
57
59
|
var _includesInstanceProperty__default = /*#__PURE__*/_interopDefault(_includesInstanceProperty);
|
|
58
60
|
var _Object$values__default = /*#__PURE__*/_interopDefault(_Object$values);
|
|
59
|
-
var _Date$now__default = /*#__PURE__*/_interopDefault(_Date$now);
|
|
60
|
-
var os__default = /*#__PURE__*/_interopDefault(os);
|
|
61
61
|
var _Object$getOwnPropertySymbols__default = /*#__PURE__*/_interopDefault(_Object$getOwnPropertySymbols);
|
|
62
62
|
var _Object$getOwnPropertyDescriptor__default = /*#__PURE__*/_interopDefault(_Object$getOwnPropertyDescriptor);
|
|
63
63
|
var _forEachInstanceProperty__default = /*#__PURE__*/_interopDefault(_forEachInstanceProperty);
|
|
64
64
|
var _Object$getOwnPropertyDescriptors__default = /*#__PURE__*/_interopDefault(_Object$getOwnPropertyDescriptors);
|
|
65
65
|
var _Object$defineProperties__default = /*#__PURE__*/_interopDefault(_Object$defineProperties);
|
|
66
66
|
var _Object$defineProperty__default = /*#__PURE__*/_interopDefault(_Object$defineProperty);
|
|
67
|
-
var
|
|
67
|
+
var _Map__default = /*#__PURE__*/_interopDefault(_Map);
|
|
68
68
|
var _Object$entries__default = /*#__PURE__*/_interopDefault(_Object$entries);
|
|
69
|
-
var _Object$assign__default = /*#__PURE__*/_interopDefault(_Object$assign);
|
|
70
69
|
var _JSON$stringify__default = /*#__PURE__*/_interopDefault(_JSON$stringify);
|
|
71
70
|
var prettier__default = /*#__PURE__*/_interopDefault(prettier);
|
|
72
71
|
|
|
73
72
|
var pkgJson = {
|
|
74
73
|
name: "@commercetools-frontend/create-mc-app",
|
|
75
|
-
version: "27.6.
|
|
74
|
+
version: "27.6.3",
|
|
76
75
|
description: "Create Merchant Center applications to quickly get up and running",
|
|
77
76
|
bugs: "https://github.com/commercetools/merchant-center-application-kit/issues",
|
|
78
77
|
repository: {
|
|
@@ -95,21 +94,22 @@ var pkgJson = {
|
|
|
95
94
|
module: "dist/commercetools-frontend-create-mc-app.esm.js",
|
|
96
95
|
bin: "./bin/cli.js",
|
|
97
96
|
dependencies: {
|
|
98
|
-
"@babel/core": "
|
|
99
|
-
"@babel/runtime": "
|
|
100
|
-
"@babel/runtime-corejs3": "
|
|
101
|
-
"@commercetools-frontend/application-config": "
|
|
102
|
-
"@types/babel__core": "
|
|
103
|
-
"@types/semver": "
|
|
104
|
-
commander: "
|
|
105
|
-
execa: "
|
|
106
|
-
listr2: "
|
|
107
|
-
prettier: "
|
|
108
|
-
semver: "
|
|
97
|
+
"@babel/core": "catalog:build",
|
|
98
|
+
"@babel/runtime": "catalog:build",
|
|
99
|
+
"@babel/runtime-corejs3": "catalog:build",
|
|
100
|
+
"@commercetools-frontend/application-config": "workspace:^",
|
|
101
|
+
"@types/babel__core": "catalog:",
|
|
102
|
+
"@types/semver": "catalog:",
|
|
103
|
+
commander: "catalog:",
|
|
104
|
+
execa: "catalog:",
|
|
105
|
+
listr2: "catalog:",
|
|
106
|
+
prettier: "catalog:lint",
|
|
107
|
+
semver: "catalog:",
|
|
108
|
+
yaml: "catalog:"
|
|
109
109
|
},
|
|
110
110
|
devDependencies: {
|
|
111
|
-
"@tsconfig/node22": "
|
|
112
|
-
"@types/prettier": "
|
|
111
|
+
"@tsconfig/node22": "catalog:",
|
|
112
|
+
"@types/prettier": "catalog:"
|
|
113
113
|
},
|
|
114
114
|
engines: {
|
|
115
115
|
node: "18.x || 20.x || >=22.0.0"
|
|
@@ -345,12 +345,22 @@ async function processOptions(projectDirectoryName, options) {
|
|
|
345
345
|
const initialProjectKey = await getInitialProjectKey(rl, options);
|
|
346
346
|
const cloudIdentifier = await getCloudIdentifier(rl, options);
|
|
347
347
|
rl.close();
|
|
348
|
+
|
|
349
|
+
// Compute the path used by `downloadTemplate` to clone the app-kit repo
|
|
350
|
+
// here so subsequent tasks (e.g. `updatePackageJson`) can read
|
|
351
|
+
// pnpm-workspace.yaml from the same checkout to resolve catalog refs.
|
|
352
|
+
// Branch names with `/` (`feat/foo`) would otherwise create a nested
|
|
353
|
+
// tmp path and break dirname/basename splits downstream — sanitize them
|
|
354
|
+
// into the folder name only.
|
|
355
|
+
const safeBranchSegment = tagOrBranchVersion.replace(/[^A-Za-z0-9._-]/g, '_');
|
|
356
|
+
const clonedRepositoryPath = path__default["default"].join(os__default["default"].tmpdir(), ['merchant-center-application-kit', '--', safeBranchSegment, '--', _Date$now__default["default"]().toString()].join(''));
|
|
348
357
|
return {
|
|
349
358
|
applicationType: options.applicationType,
|
|
350
359
|
projectDirectoryName,
|
|
351
360
|
projectDirectoryPath,
|
|
352
361
|
templateName,
|
|
353
362
|
tagOrBranchVersion,
|
|
363
|
+
clonedRepositoryPath,
|
|
354
364
|
entryPointUriPath,
|
|
355
365
|
initialProjectKey,
|
|
356
366
|
cloudIdentifier,
|
|
@@ -363,9 +373,9 @@ function downloadTemplate(options) {
|
|
|
363
373
|
return {
|
|
364
374
|
title: 'Downloading template',
|
|
365
375
|
task: () => {
|
|
366
|
-
const
|
|
367
|
-
const
|
|
368
|
-
const
|
|
376
|
+
const clonedRepositoryPath = options.clonedRepositoryPath;
|
|
377
|
+
const tmpDir = path__default["default"].dirname(clonedRepositoryPath);
|
|
378
|
+
const tmpFolderNameForClonedRepository = path__default["default"].basename(clonedRepositoryPath);
|
|
369
379
|
const templateFolderPath = path__default["default"].join(clonedRepositoryPath, options.applicationType === applicationTypes['custom-view'] ? 'custom-views-templates' : 'application-templates', options.templateName);
|
|
370
380
|
return new listr2.Listr([{
|
|
371
381
|
title: `Cloning repository using branch ${options.tagOrBranchVersion}`,
|
|
@@ -439,20 +449,120 @@ function installDependencies(options) {
|
|
|
439
449
|
}
|
|
440
450
|
|
|
441
451
|
function ownKeys(e, r) { var t = _Object$keys__default["default"](e); if (_Object$getOwnPropertySymbols__default["default"]) { var o = _Object$getOwnPropertySymbols__default["default"](e); r && (o = _filterInstanceProperty__default["default"](o).call(o, function (r) { return _Object$getOwnPropertyDescriptor__default["default"](e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
442
|
-
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
452
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var _context, _context2; var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? _forEachInstanceProperty__default["default"](_context = ownKeys(Object(t), !0)).call(_context, function (r) { _defineProperty(e, r, t[r]); }) : _Object$getOwnPropertyDescriptors__default["default"] ? _Object$defineProperties__default["default"](e, _Object$getOwnPropertyDescriptors__default["default"](t)) : _forEachInstanceProperty__default["default"](_context2 = ownKeys(Object(t))).call(_context2, function (r) { _Object$defineProperty__default["default"](e, r, _Object$getOwnPropertyDescriptor__default["default"](t, r)); }); } return e; }
|
|
453
|
+
|
|
454
|
+
// Catalog references in workspace package.json files point at entries in
|
|
455
|
+
// pnpm-workspace.yaml. They have to be flattened to concrete version
|
|
456
|
+
// specifiers in the scaffolded app because the scaffolded app is not part
|
|
457
|
+
// of any workspace.
|
|
458
|
+
//
|
|
459
|
+
// Shape: catalogName -> depName -> resolved spec. The default `catalog:`
|
|
460
|
+
// block is keyed as 'default' so `catalog:` and `catalog:<name>` lookups
|
|
461
|
+
// share one code path.
|
|
462
|
+
|
|
463
|
+
function parseCatalogs(yamlText) {
|
|
464
|
+
const doc = yaml.parse(yamlText) ?? {};
|
|
465
|
+
const out = new _Map__default["default"]();
|
|
466
|
+
if (doc.catalog) {
|
|
467
|
+
out.set('default', new _Map__default["default"](_Object$entries__default["default"](doc.catalog)));
|
|
468
|
+
}
|
|
469
|
+
for (const _ref of _Object$entries__default["default"](doc.catalogs ?? {})) {
|
|
470
|
+
var _ref2 = _slicedToArray(_ref, 2);
|
|
471
|
+
const name = _ref2[0];
|
|
472
|
+
const entries = _ref2[1];
|
|
473
|
+
out.set(name, new _Map__default["default"](_Object$entries__default["default"](entries)));
|
|
474
|
+
}
|
|
475
|
+
return out;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
// `workspace:` specifier → rewriter that takes the release version and
|
|
479
|
+
// returns the concrete spec. The supported set is data, not branching
|
|
480
|
+
// logic — extend the table to handle new protocol additions.
|
|
481
|
+
const WORKSPACE_REWRITERS = {
|
|
482
|
+
'workspace:*': v => v,
|
|
483
|
+
'workspace:^': v => `^${v}`,
|
|
484
|
+
'workspace:~': v => `~${v}`
|
|
455
485
|
};
|
|
486
|
+
|
|
487
|
+
/**
|
|
488
|
+
* Resolve a `catalog:` / `catalog:<name>` specifier to a concrete version
|
|
489
|
+
* string by looking it up in the parsed `pnpm-workspace.yaml`.
|
|
490
|
+
*
|
|
491
|
+
* @throws {Error} when the named catalog does not exist in the template's
|
|
492
|
+
* `pnpm-workspace.yaml`, or when the catalog exists but does not declare
|
|
493
|
+
* an entry for `depName`. Both cases mean the scaffold cannot produce a
|
|
494
|
+
* valid `package.json` and is unrecoverable — let it propagate.
|
|
495
|
+
*/
|
|
496
|
+
function resolveCatalogRef(spec, depName, catalogs) {
|
|
497
|
+
// `catalog:` and `catalog:default` both target the default block.
|
|
498
|
+
const name = spec === 'catalog:' || spec === 'catalog:default' ? 'default' : _sliceInstanceProperty__default["default"](spec).call(spec, 'catalog:'.length);
|
|
499
|
+
const block = catalogs.get(name);
|
|
500
|
+
if (!block) {
|
|
501
|
+
throw new Error(`Unable to resolve catalog reference "${spec}" for "${depName}": catalog "${name}" is not declared in the template's pnpm-workspace.yaml.`);
|
|
502
|
+
}
|
|
503
|
+
const resolved = block.get(depName);
|
|
504
|
+
if (!resolved) {
|
|
505
|
+
const where = name === 'default' ? 'the default catalog' : `catalogs.${name}`;
|
|
506
|
+
throw new Error(`Unable to resolve catalog reference "${spec}" for "${depName}": dep is not declared under ${where} in the template's pnpm-workspace.yaml.`);
|
|
507
|
+
}
|
|
508
|
+
return resolved;
|
|
509
|
+
}
|
|
510
|
+
function resolveSpec(depName, spec, releaseVersion, catalogs) {
|
|
511
|
+
const workspaceRewriter = WORKSPACE_REWRITERS[spec];
|
|
512
|
+
if (workspaceRewriter) return workspaceRewriter(releaseVersion);
|
|
513
|
+
if (_startsWithInstanceProperty__default["default"](spec).call(spec, 'catalog:')) return resolveCatalogRef(spec, depName, catalogs);
|
|
514
|
+
return spec;
|
|
515
|
+
}
|
|
516
|
+
function resolveDependencies() {
|
|
517
|
+
let dependencies = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
518
|
+
let releaseVersion = arguments.length > 1 ? arguments[1] : undefined;
|
|
519
|
+
let catalogs = arguments.length > 2 ? arguments[2] : undefined;
|
|
520
|
+
const out = {};
|
|
521
|
+
for (const _ref3 of _Object$entries__default["default"](dependencies)) {
|
|
522
|
+
var _ref4 = _slicedToArray(_ref3, 2);
|
|
523
|
+
const name = _ref4[0];
|
|
524
|
+
const spec = _ref4[1];
|
|
525
|
+
out[name] = resolveSpec(name, spec, releaseVersion, catalogs);
|
|
526
|
+
}
|
|
527
|
+
return out;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
// Read catalogs from the cloned template repo. Older template tags predate
|
|
531
|
+
// catalog adoption — fall back to an empty map so the workspace-only
|
|
532
|
+
// rewrite path still works.
|
|
533
|
+
function loadCatalogsFromClone(clonedRepositoryPath) {
|
|
534
|
+
const workspaceYamlPath = path__default["default"].join(clonedRepositoryPath, 'pnpm-workspace.yaml');
|
|
535
|
+
if (!fs__default["default"].existsSync(workspaceYamlPath)) return new _Map__default["default"]();
|
|
536
|
+
return parseCatalogs(fs__default["default"].readFileSync(workspaceYamlPath, {
|
|
537
|
+
encoding: 'utf8'
|
|
538
|
+
}));
|
|
539
|
+
}
|
|
540
|
+
function buildUpdatedPackageJson(appPackageJson, options, releaseVersion, catalogs) {
|
|
541
|
+
const packageManager = getPreferredPackageManager(options);
|
|
542
|
+
// Flatten workspace: and catalog: specifiers into concrete versions across
|
|
543
|
+
// every dependency section — the scaffolded app is not part of any pnpm
|
|
544
|
+
// workspace and would otherwise fail to install.
|
|
545
|
+
const resolve = deps => resolveDependencies(deps, releaseVersion, catalogs);
|
|
546
|
+
return _objectSpread(_objectSpread(_objectSpread(_objectSpread({}, appPackageJson), {}, {
|
|
547
|
+
version: '1.0.0',
|
|
548
|
+
// Given the package name is derived from the `projectDirectoryName`
|
|
549
|
+
// the latter needs to be sanitised to have a ensure a valid package name.
|
|
550
|
+
// The `projectDirectoryName` should not have restrictions (e.g. no `_`)
|
|
551
|
+
// as a result the package name potentially needs to be altered when derived.
|
|
552
|
+
name: slugify(options.projectDirectoryName),
|
|
553
|
+
description: '',
|
|
554
|
+
dependencies: resolve(appPackageJson.dependencies),
|
|
555
|
+
devDependencies: resolve(appPackageJson.devDependencies)
|
|
556
|
+
}, appPackageJson.peerDependencies && {
|
|
557
|
+
peerDependencies: resolve(appPackageJson.peerDependencies)
|
|
558
|
+
}), appPackageJson.optionalDependencies && {
|
|
559
|
+
optionalDependencies: resolve(appPackageJson.optionalDependencies)
|
|
560
|
+
}), {}, {
|
|
561
|
+
scripts: _objectSpread(_objectSpread({}, appPackageJson.scripts), {}, {
|
|
562
|
+
'start:prod:local': appPackageJson.scripts['start:prod:local'].replace('yarn', packageManager)
|
|
563
|
+
})
|
|
564
|
+
});
|
|
565
|
+
}
|
|
456
566
|
function updatePackageJson(options, releaseVersion) {
|
|
457
567
|
return {
|
|
458
568
|
title: 'Updating package.json',
|
|
@@ -461,22 +571,8 @@ function updatePackageJson(options, releaseVersion) {
|
|
|
461
571
|
const appPackageJson = JSON.parse(fs__default["default"].readFileSync(packageJsonPath, {
|
|
462
572
|
encoding: 'utf8'
|
|
463
573
|
}));
|
|
464
|
-
const
|
|
465
|
-
const updatedAppPackageJson =
|
|
466
|
-
version: '1.0.0',
|
|
467
|
-
// Given the package name is derived from the `projectDirectoryName`
|
|
468
|
-
// the latter needs to be sanitised to have a ensure a valid package name.
|
|
469
|
-
// The `projectDirectoryName` should not have restrictions (e.g. no `_`)
|
|
470
|
-
// as a result the package name potentially needs to be altered when derived.
|
|
471
|
-
name: slugify(options.projectDirectoryName),
|
|
472
|
-
description: '',
|
|
473
|
-
// Replace the package versions with the `workspace:` syntax to the real version.
|
|
474
|
-
dependencies: replaceApplicationKitPackageVersionWith(releaseVersion, appPackageJson.dependencies),
|
|
475
|
-
devDependencies: replaceApplicationKitPackageVersionWith(releaseVersion, appPackageJson.devDependencies),
|
|
476
|
-
scripts: _objectSpread(_objectSpread({}, appPackageJson.scripts), {}, {
|
|
477
|
-
'start:prod:local': appPackageJson.scripts['start:prod:local'].replace('yarn', packageManager)
|
|
478
|
-
})
|
|
479
|
-
});
|
|
574
|
+
const catalogs = loadCatalogsFromClone(options.clonedRepositoryPath);
|
|
575
|
+
const updatedAppPackageJson = buildUpdatedPackageJson(appPackageJson, options, releaseVersion, catalogs);
|
|
480
576
|
fs__default["default"].writeFileSync(packageJsonPath, _JSON$stringify__default["default"](updatedAppPackageJson, null, 2) + os__default["default"].EOL, {
|
|
481
577
|
encoding: 'utf8'
|
|
482
578
|
});
|
|
@@ -5,7 +5,9 @@ import execa from 'execa';
|
|
|
5
5
|
import semver from 'semver';
|
|
6
6
|
import _Promise from '@babel/runtime-corejs3/core-js-stable/promise';
|
|
7
7
|
import _startsWithInstanceProperty from '@babel/runtime-corejs3/core-js-stable/instance/starts-with';
|
|
8
|
+
import _Date$now from '@babel/runtime-corejs3/core-js-stable/date/now';
|
|
8
9
|
import crypto from 'node:crypto';
|
|
10
|
+
import os from 'node:os';
|
|
9
11
|
import path from 'node:path';
|
|
10
12
|
import readline from 'node:readline';
|
|
11
13
|
import { CLOUD_IDENTIFIERS } from '@commercetools-frontend/application-config';
|
|
@@ -17,8 +19,6 @@ import fs from 'node:fs';
|
|
|
17
19
|
import _Object$keys from '@babel/runtime-corejs3/core-js-stable/object/keys';
|
|
18
20
|
import _includesInstanceProperty from '@babel/runtime-corejs3/core-js-stable/instance/includes';
|
|
19
21
|
import _Object$values from '@babel/runtime-corejs3/core-js-stable/object/values';
|
|
20
|
-
import _Date$now from '@babel/runtime-corejs3/core-js-stable/date/now';
|
|
21
|
-
import os from 'node:os';
|
|
22
22
|
import _Object$getOwnPropertySymbols from '@babel/runtime-corejs3/core-js-stable/object/get-own-property-symbols';
|
|
23
23
|
import _Object$getOwnPropertyDescriptor from '@babel/runtime-corejs3/core-js-stable/object/get-own-property-descriptor';
|
|
24
24
|
import _forEachInstanceProperty from '@babel/runtime-corejs3/core-js-stable/instance/for-each';
|
|
@@ -27,16 +27,16 @@ import _Object$defineProperties from '@babel/runtime-corejs3/core-js-stable/obje
|
|
|
27
27
|
import _Object$defineProperty from '@babel/runtime-corejs3/core-js-stable/object/define-property';
|
|
28
28
|
import _defineProperty from '@babel/runtime-corejs3/helpers/esm/defineProperty';
|
|
29
29
|
import _slicedToArray from '@babel/runtime-corejs3/helpers/esm/slicedToArray';
|
|
30
|
-
import
|
|
30
|
+
import _Map from '@babel/runtime-corejs3/core-js-stable/map';
|
|
31
31
|
import _Object$entries from '@babel/runtime-corejs3/core-js-stable/object/entries';
|
|
32
|
-
import _Object$assign from '@babel/runtime-corejs3/core-js-stable/object/assign';
|
|
33
32
|
import _JSON$stringify from '@babel/runtime-corejs3/core-js-stable/json/stringify';
|
|
33
|
+
import { parse } from 'yaml';
|
|
34
34
|
import { transformFileSync, types } from '@babel/core';
|
|
35
35
|
import prettier from 'prettier';
|
|
36
36
|
|
|
37
37
|
var pkgJson = {
|
|
38
38
|
name: "@commercetools-frontend/create-mc-app",
|
|
39
|
-
version: "27.6.
|
|
39
|
+
version: "27.6.3",
|
|
40
40
|
description: "Create Merchant Center applications to quickly get up and running",
|
|
41
41
|
bugs: "https://github.com/commercetools/merchant-center-application-kit/issues",
|
|
42
42
|
repository: {
|
|
@@ -59,21 +59,22 @@ var pkgJson = {
|
|
|
59
59
|
module: "dist/commercetools-frontend-create-mc-app.esm.js",
|
|
60
60
|
bin: "./bin/cli.js",
|
|
61
61
|
dependencies: {
|
|
62
|
-
"@babel/core": "
|
|
63
|
-
"@babel/runtime": "
|
|
64
|
-
"@babel/runtime-corejs3": "
|
|
65
|
-
"@commercetools-frontend/application-config": "
|
|
66
|
-
"@types/babel__core": "
|
|
67
|
-
"@types/semver": "
|
|
68
|
-
commander: "
|
|
69
|
-
execa: "
|
|
70
|
-
listr2: "
|
|
71
|
-
prettier: "
|
|
72
|
-
semver: "
|
|
62
|
+
"@babel/core": "catalog:build",
|
|
63
|
+
"@babel/runtime": "catalog:build",
|
|
64
|
+
"@babel/runtime-corejs3": "catalog:build",
|
|
65
|
+
"@commercetools-frontend/application-config": "workspace:^",
|
|
66
|
+
"@types/babel__core": "catalog:",
|
|
67
|
+
"@types/semver": "catalog:",
|
|
68
|
+
commander: "catalog:",
|
|
69
|
+
execa: "catalog:",
|
|
70
|
+
listr2: "catalog:",
|
|
71
|
+
prettier: "catalog:lint",
|
|
72
|
+
semver: "catalog:",
|
|
73
|
+
yaml: "catalog:"
|
|
73
74
|
},
|
|
74
75
|
devDependencies: {
|
|
75
|
-
"@tsconfig/node22": "
|
|
76
|
-
"@types/prettier": "
|
|
76
|
+
"@tsconfig/node22": "catalog:",
|
|
77
|
+
"@types/prettier": "catalog:"
|
|
77
78
|
},
|
|
78
79
|
engines: {
|
|
79
80
|
node: "18.x || 20.x || >=22.0.0"
|
|
@@ -309,12 +310,22 @@ async function processOptions(projectDirectoryName, options) {
|
|
|
309
310
|
const initialProjectKey = await getInitialProjectKey(rl, options);
|
|
310
311
|
const cloudIdentifier = await getCloudIdentifier(rl, options);
|
|
311
312
|
rl.close();
|
|
313
|
+
|
|
314
|
+
// Compute the path used by `downloadTemplate` to clone the app-kit repo
|
|
315
|
+
// here so subsequent tasks (e.g. `updatePackageJson`) can read
|
|
316
|
+
// pnpm-workspace.yaml from the same checkout to resolve catalog refs.
|
|
317
|
+
// Branch names with `/` (`feat/foo`) would otherwise create a nested
|
|
318
|
+
// tmp path and break dirname/basename splits downstream — sanitize them
|
|
319
|
+
// into the folder name only.
|
|
320
|
+
const safeBranchSegment = tagOrBranchVersion.replace(/[^A-Za-z0-9._-]/g, '_');
|
|
321
|
+
const clonedRepositoryPath = path.join(os.tmpdir(), ['merchant-center-application-kit', '--', safeBranchSegment, '--', _Date$now().toString()].join(''));
|
|
312
322
|
return {
|
|
313
323
|
applicationType: options.applicationType,
|
|
314
324
|
projectDirectoryName,
|
|
315
325
|
projectDirectoryPath,
|
|
316
326
|
templateName,
|
|
317
327
|
tagOrBranchVersion,
|
|
328
|
+
clonedRepositoryPath,
|
|
318
329
|
entryPointUriPath,
|
|
319
330
|
initialProjectKey,
|
|
320
331
|
cloudIdentifier,
|
|
@@ -327,9 +338,9 @@ function downloadTemplate(options) {
|
|
|
327
338
|
return {
|
|
328
339
|
title: 'Downloading template',
|
|
329
340
|
task: () => {
|
|
330
|
-
const
|
|
331
|
-
const
|
|
332
|
-
const
|
|
341
|
+
const clonedRepositoryPath = options.clonedRepositoryPath;
|
|
342
|
+
const tmpDir = path.dirname(clonedRepositoryPath);
|
|
343
|
+
const tmpFolderNameForClonedRepository = path.basename(clonedRepositoryPath);
|
|
333
344
|
const templateFolderPath = path.join(clonedRepositoryPath, options.applicationType === applicationTypes['custom-view'] ? 'custom-views-templates' : 'application-templates', options.templateName);
|
|
334
345
|
return new Listr([{
|
|
335
346
|
title: `Cloning repository using branch ${options.tagOrBranchVersion}`,
|
|
@@ -403,20 +414,120 @@ function installDependencies(options) {
|
|
|
403
414
|
}
|
|
404
415
|
|
|
405
416
|
function ownKeys(e, r) { var t = _Object$keys(e); if (_Object$getOwnPropertySymbols) { var o = _Object$getOwnPropertySymbols(e); r && (o = _filterInstanceProperty(o).call(o, function (r) { return _Object$getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
406
|
-
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
417
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var _context, _context2; var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? _forEachInstanceProperty(_context = ownKeys(Object(t), !0)).call(_context, function (r) { _defineProperty(e, r, t[r]); }) : _Object$getOwnPropertyDescriptors ? _Object$defineProperties(e, _Object$getOwnPropertyDescriptors(t)) : _forEachInstanceProperty(_context2 = ownKeys(Object(t))).call(_context2, function (r) { _Object$defineProperty(e, r, _Object$getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
418
|
+
|
|
419
|
+
// Catalog references in workspace package.json files point at entries in
|
|
420
|
+
// pnpm-workspace.yaml. They have to be flattened to concrete version
|
|
421
|
+
// specifiers in the scaffolded app because the scaffolded app is not part
|
|
422
|
+
// of any workspace.
|
|
423
|
+
//
|
|
424
|
+
// Shape: catalogName -> depName -> resolved spec. The default `catalog:`
|
|
425
|
+
// block is keyed as 'default' so `catalog:` and `catalog:<name>` lookups
|
|
426
|
+
// share one code path.
|
|
427
|
+
|
|
428
|
+
function parseCatalogs(yamlText) {
|
|
429
|
+
const doc = parse(yamlText) ?? {};
|
|
430
|
+
const out = new _Map();
|
|
431
|
+
if (doc.catalog) {
|
|
432
|
+
out.set('default', new _Map(_Object$entries(doc.catalog)));
|
|
433
|
+
}
|
|
434
|
+
for (const _ref of _Object$entries(doc.catalogs ?? {})) {
|
|
435
|
+
var _ref2 = _slicedToArray(_ref, 2);
|
|
436
|
+
const name = _ref2[0];
|
|
437
|
+
const entries = _ref2[1];
|
|
438
|
+
out.set(name, new _Map(_Object$entries(entries)));
|
|
439
|
+
}
|
|
440
|
+
return out;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
// `workspace:` specifier → rewriter that takes the release version and
|
|
444
|
+
// returns the concrete spec. The supported set is data, not branching
|
|
445
|
+
// logic — extend the table to handle new protocol additions.
|
|
446
|
+
const WORKSPACE_REWRITERS = {
|
|
447
|
+
'workspace:*': v => v,
|
|
448
|
+
'workspace:^': v => `^${v}`,
|
|
449
|
+
'workspace:~': v => `~${v}`
|
|
419
450
|
};
|
|
451
|
+
|
|
452
|
+
/**
|
|
453
|
+
* Resolve a `catalog:` / `catalog:<name>` specifier to a concrete version
|
|
454
|
+
* string by looking it up in the parsed `pnpm-workspace.yaml`.
|
|
455
|
+
*
|
|
456
|
+
* @throws {Error} when the named catalog does not exist in the template's
|
|
457
|
+
* `pnpm-workspace.yaml`, or when the catalog exists but does not declare
|
|
458
|
+
* an entry for `depName`. Both cases mean the scaffold cannot produce a
|
|
459
|
+
* valid `package.json` and is unrecoverable — let it propagate.
|
|
460
|
+
*/
|
|
461
|
+
function resolveCatalogRef(spec, depName, catalogs) {
|
|
462
|
+
// `catalog:` and `catalog:default` both target the default block.
|
|
463
|
+
const name = spec === 'catalog:' || spec === 'catalog:default' ? 'default' : _sliceInstanceProperty(spec).call(spec, 'catalog:'.length);
|
|
464
|
+
const block = catalogs.get(name);
|
|
465
|
+
if (!block) {
|
|
466
|
+
throw new Error(`Unable to resolve catalog reference "${spec}" for "${depName}": catalog "${name}" is not declared in the template's pnpm-workspace.yaml.`);
|
|
467
|
+
}
|
|
468
|
+
const resolved = block.get(depName);
|
|
469
|
+
if (!resolved) {
|
|
470
|
+
const where = name === 'default' ? 'the default catalog' : `catalogs.${name}`;
|
|
471
|
+
throw new Error(`Unable to resolve catalog reference "${spec}" for "${depName}": dep is not declared under ${where} in the template's pnpm-workspace.yaml.`);
|
|
472
|
+
}
|
|
473
|
+
return resolved;
|
|
474
|
+
}
|
|
475
|
+
function resolveSpec(depName, spec, releaseVersion, catalogs) {
|
|
476
|
+
const workspaceRewriter = WORKSPACE_REWRITERS[spec];
|
|
477
|
+
if (workspaceRewriter) return workspaceRewriter(releaseVersion);
|
|
478
|
+
if (_startsWithInstanceProperty(spec).call(spec, 'catalog:')) return resolveCatalogRef(spec, depName, catalogs);
|
|
479
|
+
return spec;
|
|
480
|
+
}
|
|
481
|
+
function resolveDependencies() {
|
|
482
|
+
let dependencies = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
483
|
+
let releaseVersion = arguments.length > 1 ? arguments[1] : undefined;
|
|
484
|
+
let catalogs = arguments.length > 2 ? arguments[2] : undefined;
|
|
485
|
+
const out = {};
|
|
486
|
+
for (const _ref3 of _Object$entries(dependencies)) {
|
|
487
|
+
var _ref4 = _slicedToArray(_ref3, 2);
|
|
488
|
+
const name = _ref4[0];
|
|
489
|
+
const spec = _ref4[1];
|
|
490
|
+
out[name] = resolveSpec(name, spec, releaseVersion, catalogs);
|
|
491
|
+
}
|
|
492
|
+
return out;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
// Read catalogs from the cloned template repo. Older template tags predate
|
|
496
|
+
// catalog adoption — fall back to an empty map so the workspace-only
|
|
497
|
+
// rewrite path still works.
|
|
498
|
+
function loadCatalogsFromClone(clonedRepositoryPath) {
|
|
499
|
+
const workspaceYamlPath = path.join(clonedRepositoryPath, 'pnpm-workspace.yaml');
|
|
500
|
+
if (!fs.existsSync(workspaceYamlPath)) return new _Map();
|
|
501
|
+
return parseCatalogs(fs.readFileSync(workspaceYamlPath, {
|
|
502
|
+
encoding: 'utf8'
|
|
503
|
+
}));
|
|
504
|
+
}
|
|
505
|
+
function buildUpdatedPackageJson(appPackageJson, options, releaseVersion, catalogs) {
|
|
506
|
+
const packageManager = getPreferredPackageManager(options);
|
|
507
|
+
// Flatten workspace: and catalog: specifiers into concrete versions across
|
|
508
|
+
// every dependency section — the scaffolded app is not part of any pnpm
|
|
509
|
+
// workspace and would otherwise fail to install.
|
|
510
|
+
const resolve = deps => resolveDependencies(deps, releaseVersion, catalogs);
|
|
511
|
+
return _objectSpread(_objectSpread(_objectSpread(_objectSpread({}, appPackageJson), {}, {
|
|
512
|
+
version: '1.0.0',
|
|
513
|
+
// Given the package name is derived from the `projectDirectoryName`
|
|
514
|
+
// the latter needs to be sanitised to have a ensure a valid package name.
|
|
515
|
+
// The `projectDirectoryName` should not have restrictions (e.g. no `_`)
|
|
516
|
+
// as a result the package name potentially needs to be altered when derived.
|
|
517
|
+
name: slugify(options.projectDirectoryName),
|
|
518
|
+
description: '',
|
|
519
|
+
dependencies: resolve(appPackageJson.dependencies),
|
|
520
|
+
devDependencies: resolve(appPackageJson.devDependencies)
|
|
521
|
+
}, appPackageJson.peerDependencies && {
|
|
522
|
+
peerDependencies: resolve(appPackageJson.peerDependencies)
|
|
523
|
+
}), appPackageJson.optionalDependencies && {
|
|
524
|
+
optionalDependencies: resolve(appPackageJson.optionalDependencies)
|
|
525
|
+
}), {}, {
|
|
526
|
+
scripts: _objectSpread(_objectSpread({}, appPackageJson.scripts), {}, {
|
|
527
|
+
'start:prod:local': appPackageJson.scripts['start:prod:local'].replace('yarn', packageManager)
|
|
528
|
+
})
|
|
529
|
+
});
|
|
530
|
+
}
|
|
420
531
|
function updatePackageJson(options, releaseVersion) {
|
|
421
532
|
return {
|
|
422
533
|
title: 'Updating package.json',
|
|
@@ -425,22 +536,8 @@ function updatePackageJson(options, releaseVersion) {
|
|
|
425
536
|
const appPackageJson = JSON.parse(fs.readFileSync(packageJsonPath, {
|
|
426
537
|
encoding: 'utf8'
|
|
427
538
|
}));
|
|
428
|
-
const
|
|
429
|
-
const updatedAppPackageJson =
|
|
430
|
-
version: '1.0.0',
|
|
431
|
-
// Given the package name is derived from the `projectDirectoryName`
|
|
432
|
-
// the latter needs to be sanitised to have a ensure a valid package name.
|
|
433
|
-
// The `projectDirectoryName` should not have restrictions (e.g. no `_`)
|
|
434
|
-
// as a result the package name potentially needs to be altered when derived.
|
|
435
|
-
name: slugify(options.projectDirectoryName),
|
|
436
|
-
description: '',
|
|
437
|
-
// Replace the package versions with the `workspace:` syntax to the real version.
|
|
438
|
-
dependencies: replaceApplicationKitPackageVersionWith(releaseVersion, appPackageJson.dependencies),
|
|
439
|
-
devDependencies: replaceApplicationKitPackageVersionWith(releaseVersion, appPackageJson.devDependencies),
|
|
440
|
-
scripts: _objectSpread(_objectSpread({}, appPackageJson.scripts), {}, {
|
|
441
|
-
'start:prod:local': appPackageJson.scripts['start:prod:local'].replace('yarn', packageManager)
|
|
442
|
-
})
|
|
443
|
-
});
|
|
539
|
+
const catalogs = loadCatalogsFromClone(options.clonedRepositoryPath);
|
|
540
|
+
const updatedAppPackageJson = buildUpdatedPackageJson(appPackageJson, options, releaseVersion, catalogs);
|
|
444
541
|
fs.writeFileSync(packageJsonPath, _JSON$stringify(updatedAppPackageJson, null, 2) + os.EOL, {
|
|
445
542
|
encoding: 'utf8'
|
|
446
543
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@commercetools-frontend/create-mc-app",
|
|
3
|
-
"version": "27.6.
|
|
3
|
+
"version": "27.6.3",
|
|
4
4
|
"description": "Create Merchant Center applications to quickly get up and running",
|
|
5
5
|
"bugs": "https://github.com/commercetools/merchant-center-application-kit/issues",
|
|
6
6
|
"repository": {
|
|
@@ -26,14 +26,15 @@
|
|
|
26
26
|
"@babel/core": "^7.22.17",
|
|
27
27
|
"@babel/runtime": "^7.22.15",
|
|
28
28
|
"@babel/runtime-corejs3": "^7.22.15",
|
|
29
|
-
"@commercetools-frontend/application-config": "^27.6.2",
|
|
30
29
|
"@types/babel__core": "^7.20.1",
|
|
31
30
|
"@types/semver": "^7.5.1",
|
|
32
31
|
"commander": "^13.1.0",
|
|
33
32
|
"execa": "5.1.1",
|
|
34
33
|
"listr2": "5.0.8",
|
|
35
34
|
"prettier": "2.8.8",
|
|
36
|
-
"semver": "7.7.2"
|
|
35
|
+
"semver": "7.7.2",
|
|
36
|
+
"yaml": "^2.6.1",
|
|
37
|
+
"@commercetools-frontend/application-config": "^27.6.3"
|
|
37
38
|
},
|
|
38
39
|
"devDependencies": {
|
|
39
40
|
"@tsconfig/node22": "^22.0.0",
|
package/src/process-options.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import crypto from 'node:crypto';
|
|
2
|
+
import os from 'node:os';
|
|
2
3
|
import path from 'node:path';
|
|
3
4
|
import readline, { type Interface } from 'node:readline';
|
|
4
5
|
import { CLOUD_IDENTIFIERS } from '@commercetools-frontend/application-config';
|
|
@@ -118,12 +119,31 @@ async function processOptions(
|
|
|
118
119
|
const cloudIdentifier = await getCloudIdentifier(rl, options);
|
|
119
120
|
rl.close();
|
|
120
121
|
|
|
122
|
+
// Compute the path used by `downloadTemplate` to clone the app-kit repo
|
|
123
|
+
// here so subsequent tasks (e.g. `updatePackageJson`) can read
|
|
124
|
+
// pnpm-workspace.yaml from the same checkout to resolve catalog refs.
|
|
125
|
+
// Branch names with `/` (`feat/foo`) would otherwise create a nested
|
|
126
|
+
// tmp path and break dirname/basename splits downstream — sanitize them
|
|
127
|
+
// into the folder name only.
|
|
128
|
+
const safeBranchSegment = tagOrBranchVersion.replace(/[^A-Za-z0-9._-]/g, '_');
|
|
129
|
+
const clonedRepositoryPath = path.join(
|
|
130
|
+
os.tmpdir(),
|
|
131
|
+
[
|
|
132
|
+
'merchant-center-application-kit',
|
|
133
|
+
'--',
|
|
134
|
+
safeBranchSegment,
|
|
135
|
+
'--',
|
|
136
|
+
Date.now().toString(),
|
|
137
|
+
].join('')
|
|
138
|
+
);
|
|
139
|
+
|
|
121
140
|
return {
|
|
122
141
|
applicationType: options.applicationType,
|
|
123
142
|
projectDirectoryName,
|
|
124
143
|
projectDirectoryPath,
|
|
125
144
|
templateName,
|
|
126
145
|
tagOrBranchVersion,
|
|
146
|
+
clonedRepositoryPath,
|
|
127
147
|
entryPointUriPath,
|
|
128
148
|
initialProjectKey,
|
|
129
149
|
cloudIdentifier,
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import os from 'node:os';
|
|
2
1
|
import path from 'node:path';
|
|
3
2
|
import execa from 'execa';
|
|
4
3
|
import { Listr, type ListrTask } from 'listr2';
|
|
@@ -13,18 +12,10 @@ function downloadTemplate(options: TCliTaskOptions): ListrTask {
|
|
|
13
12
|
return {
|
|
14
13
|
title: 'Downloading template',
|
|
15
14
|
task: () => {
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
options.tagOrBranchVersion,
|
|
21
|
-
'--',
|
|
22
|
-
Date.now().toString(),
|
|
23
|
-
].join('');
|
|
24
|
-
const clonedRepositoryPath = path.join(
|
|
25
|
-
tmpDir,
|
|
26
|
-
tmpFolderNameForClonedRepository
|
|
27
|
-
);
|
|
15
|
+
const clonedRepositoryPath = options.clonedRepositoryPath;
|
|
16
|
+
const tmpDir = path.dirname(clonedRepositoryPath);
|
|
17
|
+
const tmpFolderNameForClonedRepository =
|
|
18
|
+
path.basename(clonedRepositoryPath);
|
|
28
19
|
const templateFolderPath = path.join(
|
|
29
20
|
clonedRepositoryPath,
|
|
30
21
|
options.applicationType === applicationTypes['custom-view']
|
|
@@ -2,26 +2,169 @@ import fs from 'node:fs';
|
|
|
2
2
|
import os from 'node:os';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import type { ListrTask } from 'listr2';
|
|
5
|
+
import { parse as parseYaml } from 'yaml';
|
|
5
6
|
import type { TCliTaskOptions } from '../types';
|
|
6
7
|
import { getPreferredPackageManager, slugify } from '../utils';
|
|
7
8
|
|
|
8
|
-
|
|
9
|
+
// Catalog references in workspace package.json files point at entries in
|
|
10
|
+
// pnpm-workspace.yaml. They have to be flattened to concrete version
|
|
11
|
+
// specifiers in the scaffolded app because the scaffolded app is not part
|
|
12
|
+
// of any workspace.
|
|
13
|
+
//
|
|
14
|
+
// Shape: catalogName -> depName -> resolved spec. The default `catalog:`
|
|
15
|
+
// block is keyed as 'default' so `catalog:` and `catalog:<name>` lookups
|
|
16
|
+
// share one code path.
|
|
17
|
+
type Catalogs = Map<string, Map<string, string>>;
|
|
18
|
+
|
|
19
|
+
type WorkspaceYaml = {
|
|
20
|
+
catalog?: Record<string, string>;
|
|
21
|
+
catalogs?: Record<string, Record<string, string>>;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
function parseCatalogs(yamlText: string): Catalogs {
|
|
25
|
+
const doc = (parseYaml(yamlText) ?? {}) as WorkspaceYaml;
|
|
26
|
+
const out: Catalogs = new Map();
|
|
27
|
+
if (doc.catalog) {
|
|
28
|
+
out.set('default', new Map(Object.entries(doc.catalog)));
|
|
29
|
+
}
|
|
30
|
+
for (const [name, entries] of Object.entries(doc.catalogs ?? {})) {
|
|
31
|
+
out.set(name, new Map(Object.entries(entries)));
|
|
32
|
+
}
|
|
33
|
+
return out;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// `workspace:` specifier → rewriter that takes the release version and
|
|
37
|
+
// returns the concrete spec. The supported set is data, not branching
|
|
38
|
+
// logic — extend the table to handle new protocol additions.
|
|
39
|
+
const WORKSPACE_REWRITERS: Record<string, (releaseVersion: string) => string> =
|
|
40
|
+
{
|
|
41
|
+
'workspace:*': (v) => v,
|
|
42
|
+
'workspace:^': (v) => `^${v}`,
|
|
43
|
+
'workspace:~': (v) => `~${v}`,
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Resolve a `catalog:` / `catalog:<name>` specifier to a concrete version
|
|
48
|
+
* string by looking it up in the parsed `pnpm-workspace.yaml`.
|
|
49
|
+
*
|
|
50
|
+
* @throws {Error} when the named catalog does not exist in the template's
|
|
51
|
+
* `pnpm-workspace.yaml`, or when the catalog exists but does not declare
|
|
52
|
+
* an entry for `depName`. Both cases mean the scaffold cannot produce a
|
|
53
|
+
* valid `package.json` and is unrecoverable — let it propagate.
|
|
54
|
+
*/
|
|
55
|
+
function resolveCatalogRef(
|
|
56
|
+
spec: string,
|
|
57
|
+
depName: string,
|
|
58
|
+
catalogs: Catalogs
|
|
59
|
+
): string {
|
|
60
|
+
// `catalog:` and `catalog:default` both target the default block.
|
|
61
|
+
const name =
|
|
62
|
+
spec === 'catalog:' || spec === 'catalog:default'
|
|
63
|
+
? 'default'
|
|
64
|
+
: spec.slice('catalog:'.length);
|
|
65
|
+
const block = catalogs.get(name);
|
|
66
|
+
if (!block) {
|
|
67
|
+
throw new Error(
|
|
68
|
+
`Unable to resolve catalog reference "${spec}" for "${depName}": catalog "${name}" is not declared in the template's pnpm-workspace.yaml.`
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
const resolved = block.get(depName);
|
|
72
|
+
if (!resolved) {
|
|
73
|
+
const where =
|
|
74
|
+
name === 'default' ? 'the default catalog' : `catalogs.${name}`;
|
|
75
|
+
throw new Error(
|
|
76
|
+
`Unable to resolve catalog reference "${spec}" for "${depName}": dep is not declared under ${where} in the template's pnpm-workspace.yaml.`
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
return resolved;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function resolveSpec(
|
|
83
|
+
depName: string,
|
|
84
|
+
spec: string,
|
|
9
85
|
releaseVersion: string,
|
|
10
|
-
|
|
11
|
-
)
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
86
|
+
catalogs: Catalogs
|
|
87
|
+
): string {
|
|
88
|
+
const workspaceRewriter = WORKSPACE_REWRITERS[spec];
|
|
89
|
+
if (workspaceRewriter) return workspaceRewriter(releaseVersion);
|
|
90
|
+
if (spec.startsWith('catalog:'))
|
|
91
|
+
return resolveCatalogRef(spec, depName, catalogs);
|
|
92
|
+
return spec;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function resolveDependencies(
|
|
96
|
+
dependencies: Record<string, string> = {},
|
|
97
|
+
releaseVersion: string,
|
|
98
|
+
catalogs: Catalogs
|
|
99
|
+
): Record<string, string> {
|
|
100
|
+
const out: Record<string, string> = {};
|
|
101
|
+
for (const [name, spec] of Object.entries(dependencies)) {
|
|
102
|
+
out[name] = resolveSpec(name, spec, releaseVersion, catalogs);
|
|
103
|
+
}
|
|
104
|
+
return out;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Read catalogs from the cloned template repo. Older template tags predate
|
|
108
|
+
// catalog adoption — fall back to an empty map so the workspace-only
|
|
109
|
+
// rewrite path still works.
|
|
110
|
+
function loadCatalogsFromClone(clonedRepositoryPath: string): Catalogs {
|
|
111
|
+
const workspaceYamlPath = path.join(
|
|
112
|
+
clonedRepositoryPath,
|
|
113
|
+
'pnpm-workspace.yaml'
|
|
24
114
|
);
|
|
115
|
+
if (!fs.existsSync(workspaceYamlPath)) return new Map();
|
|
116
|
+
return parseCatalogs(
|
|
117
|
+
fs.readFileSync(workspaceYamlPath, { encoding: 'utf8' })
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
type TAppPackageJson = {
|
|
122
|
+
dependencies?: Record<string, string>;
|
|
123
|
+
devDependencies?: Record<string, string>;
|
|
124
|
+
peerDependencies?: Record<string, string>;
|
|
125
|
+
optionalDependencies?: Record<string, string>;
|
|
126
|
+
scripts: Record<string, string> & { 'start:prod:local': string };
|
|
127
|
+
[key: string]: unknown;
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
function buildUpdatedPackageJson(
|
|
131
|
+
appPackageJson: TAppPackageJson,
|
|
132
|
+
options: TCliTaskOptions,
|
|
133
|
+
releaseVersion: string,
|
|
134
|
+
catalogs: Catalogs
|
|
135
|
+
): TAppPackageJson {
|
|
136
|
+
const packageManager = getPreferredPackageManager(options);
|
|
137
|
+
// Flatten workspace: and catalog: specifiers into concrete versions across
|
|
138
|
+
// every dependency section — the scaffolded app is not part of any pnpm
|
|
139
|
+
// workspace and would otherwise fail to install.
|
|
140
|
+
const resolve = (deps?: Record<string, string>) =>
|
|
141
|
+
resolveDependencies(deps, releaseVersion, catalogs);
|
|
142
|
+
return {
|
|
143
|
+
...appPackageJson,
|
|
144
|
+
version: '1.0.0',
|
|
145
|
+
// Given the package name is derived from the `projectDirectoryName`
|
|
146
|
+
// the latter needs to be sanitised to have a ensure a valid package name.
|
|
147
|
+
// The `projectDirectoryName` should not have restrictions (e.g. no `_`)
|
|
148
|
+
// as a result the package name potentially needs to be altered when derived.
|
|
149
|
+
name: slugify(options.projectDirectoryName),
|
|
150
|
+
description: '',
|
|
151
|
+
dependencies: resolve(appPackageJson.dependencies),
|
|
152
|
+
devDependencies: resolve(appPackageJson.devDependencies),
|
|
153
|
+
...(appPackageJson.peerDependencies && {
|
|
154
|
+
peerDependencies: resolve(appPackageJson.peerDependencies),
|
|
155
|
+
}),
|
|
156
|
+
...(appPackageJson.optionalDependencies && {
|
|
157
|
+
optionalDependencies: resolve(appPackageJson.optionalDependencies),
|
|
158
|
+
}),
|
|
159
|
+
scripts: {
|
|
160
|
+
...appPackageJson.scripts,
|
|
161
|
+
'start:prod:local': appPackageJson.scripts['start:prod:local'].replace(
|
|
162
|
+
'yarn',
|
|
163
|
+
packageManager
|
|
164
|
+
),
|
|
165
|
+
},
|
|
166
|
+
};
|
|
167
|
+
}
|
|
25
168
|
|
|
26
169
|
function updatePackageJson(
|
|
27
170
|
options: TCliTaskOptions,
|
|
@@ -37,33 +180,13 @@ function updatePackageJson(
|
|
|
37
180
|
const appPackageJson = JSON.parse(
|
|
38
181
|
fs.readFileSync(packageJsonPath, { encoding: 'utf8' })
|
|
39
182
|
);
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
// as a result the package name potentially needs to be altered when derived.
|
|
48
|
-
name: slugify(options.projectDirectoryName),
|
|
49
|
-
description: '',
|
|
50
|
-
// Replace the package versions with the `workspace:` syntax to the real version.
|
|
51
|
-
dependencies: replaceApplicationKitPackageVersionWith(
|
|
52
|
-
releaseVersion,
|
|
53
|
-
appPackageJson.dependencies
|
|
54
|
-
),
|
|
55
|
-
devDependencies: replaceApplicationKitPackageVersionWith(
|
|
56
|
-
releaseVersion,
|
|
57
|
-
appPackageJson.devDependencies
|
|
58
|
-
),
|
|
59
|
-
scripts: {
|
|
60
|
-
...appPackageJson.scripts,
|
|
61
|
-
'start:prod:local': appPackageJson.scripts[
|
|
62
|
-
'start:prod:local'
|
|
63
|
-
].replace('yarn', packageManager),
|
|
64
|
-
},
|
|
65
|
-
});
|
|
66
|
-
|
|
183
|
+
const catalogs = loadCatalogsFromClone(options.clonedRepositoryPath);
|
|
184
|
+
const updatedAppPackageJson = buildUpdatedPackageJson(
|
|
185
|
+
appPackageJson,
|
|
186
|
+
options,
|
|
187
|
+
releaseVersion,
|
|
188
|
+
catalogs
|
|
189
|
+
);
|
|
67
190
|
fs.writeFileSync(
|
|
68
191
|
packageJsonPath,
|
|
69
192
|
JSON.stringify(updatedAppPackageJson, null, 2) + os.EOL,
|
package/src/types.ts
CHANGED
|
@@ -26,6 +26,10 @@ export type TCliTaskOptions = {
|
|
|
26
26
|
projectDirectoryPath: string;
|
|
27
27
|
templateName: TCliCommandOptions['template'];
|
|
28
28
|
tagOrBranchVersion: string;
|
|
29
|
+
// Absolute path to the temporary directory where the app-kit repo is
|
|
30
|
+
// cloned by `downloadTemplate`. Subsequent tasks read pnpm-workspace.yaml
|
|
31
|
+
// from here to resolve catalog references in the scaffolded package.json.
|
|
32
|
+
clonedRepositoryPath: string;
|
|
29
33
|
entryPointUriPath?: string;
|
|
30
34
|
initialProjectKey: string;
|
|
31
35
|
cloudIdentifier: string;
|