contensis-cli 1.1.2-beta.1 → 1.1.2-beta.11

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.
Files changed (54) hide show
  1. package/dist/commands/copy.js +70 -0
  2. package/dist/commands/copy.js.map +7 -0
  3. package/dist/commands/create.js +1 -1
  4. package/dist/commands/create.js.map +2 -2
  5. package/dist/commands/dev.js +11 -4
  6. package/dist/commands/dev.js.map +2 -2
  7. package/dist/commands/get.js +1 -0
  8. package/dist/commands/get.js.map +2 -2
  9. package/dist/commands/globalOptions.js +24 -3
  10. package/dist/commands/globalOptions.js.map +2 -2
  11. package/dist/commands/import.js +1 -6
  12. package/dist/commands/import.js.map +2 -2
  13. package/dist/commands/index.js +7 -3
  14. package/dist/commands/index.js.map +2 -2
  15. package/dist/factories/RequestHandlerFactory.js +24 -13
  16. package/dist/factories/RequestHandlerFactory.js.map +2 -2
  17. package/dist/localisation/en-GB.js +3 -1
  18. package/dist/localisation/en-GB.js.map +2 -2
  19. package/dist/mappers/DevRequests-to-RequestHanderCliArgs.js +128 -88
  20. package/dist/mappers/DevRequests-to-RequestHanderCliArgs.js.map +3 -3
  21. package/dist/providers/GitHubCliModuleProvider.js +14 -4
  22. package/dist/providers/GitHubCliModuleProvider.js.map +2 -2
  23. package/dist/providers/file-provider.js +3 -0
  24. package/dist/providers/file-provider.js.map +2 -2
  25. package/dist/services/ContensisCliService.js +61 -0
  26. package/dist/services/ContensisCliService.js.map +2 -2
  27. package/dist/services/ContensisDevService.js +30 -5
  28. package/dist/services/ContensisDevService.js.map +3 -3
  29. package/dist/shell.js +1 -0
  30. package/dist/shell.js.map +2 -2
  31. package/dist/util/api-ids.js +110 -0
  32. package/dist/util/api-ids.js.map +7 -0
  33. package/dist/util/console.printer.js.map +2 -2
  34. package/dist/version.js +1 -1
  35. package/dist/version.js.map +1 -1
  36. package/package.json +2 -3
  37. package/src/commands/copy.ts +79 -0
  38. package/src/commands/create.ts +1 -2
  39. package/src/commands/dev.ts +14 -6
  40. package/src/commands/get.ts +12 -11
  41. package/src/commands/globalOptions.ts +25 -2
  42. package/src/commands/import.ts +4 -8
  43. package/src/commands/index.ts +7 -3
  44. package/src/factories/RequestHandlerFactory.ts +38 -17
  45. package/src/localisation/en-GB.ts +3 -2
  46. package/src/mappers/DevRequests-to-RequestHanderCliArgs.ts +147 -92
  47. package/src/providers/GitHubCliModuleProvider.ts +19 -6
  48. package/src/providers/file-provider.ts +4 -0
  49. package/src/services/ContensisCliService.ts +82 -0
  50. package/src/services/ContensisDevService.ts +37 -6
  51. package/src/shell.ts +2 -1
  52. package/src/util/api-ids.ts +111 -0
  53. package/src/util/console.printer.ts +2 -1
  54. package/src/version.ts +1 -1
@@ -1,4 +1,5 @@
1
1
  import { ContensisMigrationService } from 'migratortron';
2
+ import PQueue from 'p-queue';
2
3
  import ContensisCli from '~/services/ContensisCliService';
3
4
 
4
5
  type EndpointJson = {
@@ -32,114 +33,168 @@ type RendererRuleJson = {
32
33
  interface ISiteConfigYaml {
33
34
  alias: string;
34
35
  projectId: string;
35
- accessToken: string;
36
+ iisHostname: string;
37
+ podClusterId: string;
38
+ accessToken: string; // needed?
36
39
  clientId: string;
37
40
  sharedSecret: string;
38
41
  blocks: BlockJson[];
39
42
  renderers: RendererJson[];
40
43
  }
41
44
 
42
- export const buildSiteConfig = async (cli: ContensisCli) => {
43
- const { currentEnv, env, log, messages } = cli;
44
- const siteConfig: ISiteConfigYaml = {
45
- alias: cli.currentEnv,
46
- projectId: cli.currentProject,
47
- accessToken: '',
48
- clientId: '',
49
- sharedSecret: '',
50
- blocks: [],
51
- renderers: [],
45
+ class RequestHandlerArgs {
46
+ private cli;
47
+ args?: string[];
48
+ siteConfig?: ISiteConfigYaml;
49
+
50
+ constructor(cli: ContensisCli) {
51
+ this.cli = cli;
52
+ }
53
+
54
+ Create = async () => {
55
+ this.siteConfig = await this.buildSiteConfig();
56
+ await this.cli.Login(this.cli.env.lastUserId, { silent: true }); // to hydrate the auth service
57
+ this.args = this.getArgs();
52
58
  };
53
59
 
54
- const getBlocks = async (contensis: ContensisMigrationService) => {
55
- const [err, blocksRaw] = await contensis.blocks.GetBlocks();
56
- if (err) log.error(messages.blocks.noList(currentEnv, env.currentProject));
60
+ buildSiteConfig = async () => {
61
+ const { currentEnv, currentProject, env, log, messages, urls } = this.cli;
62
+ const contensis = await this.cli.ConnectContensis();
57
63
 
58
- // const blocksRaw = await cli.PrintBlocks();
64
+ const siteConfig: ISiteConfigYaml = {
65
+ alias: currentEnv,
66
+ projectId: currentProject,
67
+ iisHostname: urls?.iisPreviewWeb.split('//')[1] || '',
68
+ podClusterId: 'hq',
69
+ accessToken: '',
70
+ clientId: '',
71
+ sharedSecret: '',
72
+ blocks: [],
73
+ renderers: [],
74
+ };
59
75
 
60
- const blocks: BlockJson[] = [];
61
- for (const block of blocksRaw || []) {
62
- // Retrieve block version
63
- const [err, versions] = await contensis.blocks.GetBlockVersions(
64
- block.id,
65
- 'default',
66
- 'latest'
67
- );
68
- if (err || versions?.length === 0)
69
- log.warning(
70
- messages.blocks.noGet(
76
+ const getBlocks = async (contensis: ContensisMigrationService) => {
77
+ const [err, blocksRaw] = await contensis.blocks.GetBlocks();
78
+ if (err)
79
+ log.error(messages.blocks.noList(currentEnv, env.currentProject));
80
+
81
+ // const blocksRaw = await cli.PrintBlocks();
82
+
83
+ const blocks: BlockJson[] = [];
84
+ const queue = new PQueue({ concurrency: 4 });
85
+ for (const block of blocksRaw || []) {
86
+ queue.add(async () => {
87
+ // Retrieve block version
88
+ const [err, versions] = await contensis.blocks.GetBlockVersions(
71
89
  block.id,
72
90
  'default',
73
- 'latest',
74
- currentEnv,
75
- env.currentProject
76
- )
77
- );
78
- if (versions?.[0]) {
79
- const v = versions[0];
80
- blocks.push({
81
- id: v.id,
82
- baseUri: v.previewUrl,
83
- staticPaths: v.staticPaths,
84
- endpoints: v.endpoints,
85
- versionNo: v.version.versionNo,
86
- branch: v.source.branch,
91
+ 'latest'
92
+ );
93
+ if (err || versions?.length === 0)
94
+ log.warning(
95
+ messages.blocks.noGet(
96
+ block.id,
97
+ 'default',
98
+ 'latest',
99
+ currentEnv,
100
+ env.currentProject
101
+ )
102
+ );
103
+ if (versions?.[0]) {
104
+ const v = versions[0];
105
+ blocks.push({
106
+ id: v.id,
107
+ baseUri: v.previewUrl,
108
+ staticPaths: v.staticPaths,
109
+ endpoints: v.endpoints,
110
+ versionNo: v.version.versionNo,
111
+ branch: v.source.branch,
112
+ });
113
+ }
87
114
  });
88
115
  }
116
+
117
+ await queue.onIdle();
118
+ return blocks;
119
+ };
120
+
121
+ if (contensis) {
122
+ const [blocks, renderers] = await Promise.all([
123
+ getBlocks(contensis),
124
+ contensis.renderers.GetRenderers(),
125
+ ]);
126
+
127
+ siteConfig.blocks = blocks;
128
+ siteConfig.renderers = renderers?.[1]
129
+ ?.filter(r => blocks.find(b => b.id === r.id))
130
+ .map(r => ({
131
+ id: r.id,
132
+ name: r.name,
133
+ assignedContentTypes: r.assignedContentTypes,
134
+ rules: r.rules,
135
+ }));
89
136
  }
90
- return blocks;
137
+ return siteConfig;
91
138
  };
92
139
 
93
- const contensis = await cli.ConnectContensis();
94
- if (contensis) {
95
- const [blocks, renderers] = await Promise.all([
96
- getBlocks(contensis),
97
- contensis.renderers.GetRenderers(),
98
- ]);
99
-
100
- siteConfig.blocks = blocks;
101
- siteConfig.renderers = renderers?.[1]?.map(r => ({
102
- id: r.id,
103
- name: r.name,
104
- assignedContentTypes: r.assignedContentTypes,
105
- rules: r.rules,
106
- }));
107
- }
108
- return siteConfig;
109
- };
140
+ getArgs = (overrideArgs: string[] = []) => {
141
+ const args = overrideArgs
142
+ ? typeof overrideArgs?.[0] === 'string' &&
143
+ overrideArgs[0].includes(' ', 2)
144
+ ? overrideArgs[0].split(' ')
145
+ : overrideArgs
146
+ : []; // args could be [ '-c .\\site_config.yaml' ] or [ '-c', '.\\site_config.yaml' ]
110
147
 
111
- export const requestHandlerCliArgs = async (
112
- cli: ContensisCli,
113
- overrideArgs: string[] = []
114
- ) => {
115
- const args = overrideArgs
116
- ? typeof overrideArgs?.[0] === 'string' && overrideArgs[0].includes(' ', 2)
117
- ? overrideArgs[0].split(' ')
118
- : overrideArgs
119
- : []; // args could be [ '-c .\\site_config.yaml' ] or [ '-c', '.\\site_config.yaml' ]
120
-
121
- const siteConfig = await buildSiteConfig(cli);
122
- // Add required args
123
- if (!args.find(a => a === '--alias')) args.push('--alias', cli.currentEnv);
124
- if (!args.find(a => a === '--project-api-id'))
125
- args.push('--project-api-id', cli.currentProject);
126
- if (!args.find(a => a === '--blocks-json'))
127
- args.push('--blocks-json', JSON.stringify(siteConfig.blocks));
128
- if (!args.find(a => a === '--renderers-json'))
129
- args.push('--renderers-json', JSON.stringify(siteConfig.renderers));
130
-
131
- await cli.Login(cli.env.lastUserId, { silent: true }); // to hydrate the auth service
132
- const client = cli.auth?.clientDetails;
133
- if (client) {
134
- if (!args.find(a => a === '--client-id') && 'clientId' in client)
135
- args.push('--client-id', client.clientId);
136
- if (!args.find(a => a === '--client-secret') && 'clientSecret' in client)
137
- args.push('--client-secret', client.clientSecret);
138
- if (!args.find(a => a === '--username') && 'username' in client)
139
- args.push('--username', client.username);
140
- if (!args.find(a => a === '--password') && 'password' in client)
141
- args.push('--password', client.password);
142
- }
148
+ const { cli, siteConfig } = this;
149
+ if (siteConfig) {
150
+ // Add required args
151
+ if (!args.find(a => a === '--alias'))
152
+ args.push('--alias', cli.currentEnv);
153
+ if (!args.find(a => a === '--project-api-id'))
154
+ args.push('--project-api-id', cli.currentProject);
155
+ if (!args.find(a => a === '--iis-hostname'))
156
+ args.push('--iis-hostname', siteConfig.iisHostname);
157
+ if (!args.find(a => a === '--pod-cluster-id'))
158
+ args.push('--pod-cluster-id', siteConfig.podClusterId);
159
+ if (!args.find(a => a === '--blocks-json'))
160
+ args.push('--blocks-json', JSON.stringify(siteConfig.blocks));
161
+ if (!args.find(a => a === '--renderers-json'))
162
+ args.push('--renderers-json', JSON.stringify(siteConfig.renderers));
163
+ }
143
164
 
144
- return args;
145
- };
165
+ const client = cli.auth?.clientDetails;
166
+ if (client) {
167
+ if (!args.find(a => a === '--client-id') && 'clientId' in client)
168
+ args.push('--client-id', client.clientId);
169
+ if (!args.find(a => a === '--client-secret') && 'clientSecret' in client)
170
+ args.push('--client-secret', client.clientSecret);
171
+ if (!args.find(a => a === '--username') && 'username' in client)
172
+ args.push('--username', client.username);
173
+ if (!args.find(a => a === '--password') && 'password' in client)
174
+ args.push('--password', client.password);
175
+ }
176
+
177
+ return args;
178
+ };
179
+
180
+ overrideBlock = (blockId: string, overrideUri: string) => {
181
+ if (blockId && blockId !== 'none') {
182
+ const blockIndex = this.siteConfig?.blocks.findIndex(
183
+ b => b.id.toLowerCase() === blockId.toLowerCase()
184
+ );
185
+ if (
186
+ typeof blockIndex === 'number' &&
187
+ !isNaN(blockIndex) &&
188
+ this.siteConfig?.blocks[blockIndex]
189
+ ) {
190
+ this.siteConfig.blocks[blockIndex].baseUri = overrideUri;
191
+ // this.siteConfig.blocks[blockIndex].staticPaths.push(
192
+ // ...['/static/*', '/image-library/*']
193
+ // );
194
+ this.siteConfig.blocks[blockIndex].staticPaths.push('/*.js');
195
+ }
196
+ }
197
+ };
198
+ }
199
+
200
+ export default RequestHandlerArgs;
@@ -3,6 +3,7 @@ import Zip from 'adm-zip';
3
3
  import type { Endpoints } from '@octokit/types';
4
4
  import HttpProvider from '~/providers/HttpProvider';
5
5
  import {
6
+ addExecutePermission,
6
7
  checkDir,
7
8
  joinPath,
8
9
  removeDirectory,
@@ -37,7 +38,7 @@ class GitHubCliModuleProvider {
37
38
  this.repo = repo;
38
39
  }
39
40
 
40
- async FindLatestRelease() {
41
+ async FindLatestRelease(version?: string) {
41
42
  const { http, latest_release_url, releases_url } = this;
42
43
  // return latest tag version is:
43
44
 
@@ -55,14 +56,18 @@ class GitHubCliModuleProvider {
55
56
  throw new Error(`Unable to get releases`, { cause: releasesErr });
56
57
  } else if (!releases || releases.length === 0)
57
58
  throw new Error(`No releases available`);
58
- else if (latestErr && !latest) {
59
+ else if (version) {
60
+ const release = releases.find(
61
+ r => r.tag_name.toLowerCase() === version.toLowerCase()
62
+ );
63
+ if (release) return release;
64
+ else throw new Error(`No release for ${version} found`);
65
+ } else if (latestErr && !latest) {
59
66
  if (latestResponse?.status === 404 && releases?.length) {
60
67
  // No latest release, check releases for prerelease version, fallback to last release
61
68
  const release = releases.find(r => r.prerelease) || releases[0];
62
69
 
63
- if (release) {
64
- return release;
65
- }
70
+ if (release) return release;
66
71
  }
67
72
  } else {
68
73
  return latest;
@@ -72,10 +77,16 @@ class GitHubCliModuleProvider {
72
77
  async DownloadRelease(
73
78
  release: GitHubApiRelease,
74
79
  {
80
+ cmd,
75
81
  path,
76
82
  platforms,
77
83
  unzip = true,
78
- }: { path: string; unzip?: boolean; platforms: [NodeJS.Platform, string][] }
84
+ }: {
85
+ cmd: string;
86
+ path: string;
87
+ unzip?: boolean;
88
+ platforms: [NodeJS.Platform, string][];
89
+ }
79
90
  ) {
80
91
  // find os-specific asset
81
92
  const platform = platforms.find(p => p[0] === os.platform()) || [
@@ -102,6 +113,8 @@ class GitHubCliModuleProvider {
102
113
  // delete the downloaded zip file
103
114
  removeFile(filePath);
104
115
  }
116
+
117
+ if (os.platform() !== 'win32') addExecutePermission(joinPath(path, cmd));
105
118
  } else
106
119
  throw new Error(
107
120
  `no asset found in release ${
@@ -93,6 +93,10 @@ export const cwdPath = (filePath: string) =>
93
93
 
94
94
  export const joinPath = path.join;
95
95
 
96
+ export const addExecutePermission = (filePath: string) =>
97
+ // Fails in windows with `TypeError [ERR_INVALID_ARG_TYPE]: The "mode" argument must be of type number. Received undefined`
98
+ fs.chmodSync(filePath, fs.constants.S_IRWXU);
99
+
96
100
  type DetectedFileType =
97
101
  | { type: 'json'; contents: any }
98
102
  | { type: 'xml' | 'csv'; contents: string };
@@ -36,6 +36,7 @@ import {
36
36
  tryStringify,
37
37
  url,
38
38
  } from '~/util';
39
+ import { sanitiseIds } from '~/util/api-ids';
39
40
  import {
40
41
  printBlockVersion,
41
42
  printEntriesMigrateResult,
@@ -142,6 +143,14 @@ class ContensisCli {
142
143
  this.session = new SessionCacheProvider();
143
144
 
144
145
  this.contensisOpts = contensisOpts;
146
+
147
+ // Explicitly sanitise supplied fields to api-friendly ids
148
+ if (Array.isArray(this.contensisOpts.query?.fields)) {
149
+ this.contensisOpts.query.fields = sanitiseIds(
150
+ this.contensisOpts.query.fields
151
+ );
152
+ }
153
+
145
154
  this.format = outputOpts?.format;
146
155
  this.output =
147
156
  outputOpts?.output && path.join(process.cwd(), outputOpts.output);
@@ -1788,6 +1797,79 @@ class ContensisCli {
1788
1797
  }
1789
1798
  };
1790
1799
 
1800
+ CopyEntryField = async ({
1801
+ commit,
1802
+ fromFile,
1803
+ logOutput,
1804
+ }: {
1805
+ commit: boolean;
1806
+ fromFile: string;
1807
+ logOutput: string;
1808
+ }) => {
1809
+ const { currentEnv, currentProject, log, messages } = this;
1810
+
1811
+ const contensis = await this.ConnectContensisImport({
1812
+ commit,
1813
+ fromFile,
1814
+ importDataType: 'entries',
1815
+ });
1816
+
1817
+ if (contensis) {
1818
+ log.line();
1819
+ if (contensis.isPreview) {
1820
+ console.log(log.successText(` -- IMPORT PREVIEW -- `));
1821
+ } else {
1822
+ console.log(log.warningText(` *** COMMITTING IMPORT *** `));
1823
+ }
1824
+
1825
+ const [err, result] = await to(
1826
+ contensis.content.copy.MigrateFieldContent()
1827
+ );
1828
+
1829
+ if (err) logError(err);
1830
+ if (result)
1831
+ await this.HandleFormattingAndOutput(result, () => {
1832
+ // print the migrateResult to console
1833
+ printEntriesMigrateResult(this, result, {
1834
+ showAll: logOutput === 'all',
1835
+ showDiff: logOutput === 'all' || logOutput === 'changes',
1836
+ showChanged: logOutput === 'changes',
1837
+ });
1838
+ });
1839
+
1840
+ if (
1841
+ result &&
1842
+ !err &&
1843
+ !result.errors?.length &&
1844
+ ((!commit && result.entriesToMigrate[currentProject].totalCount) ||
1845
+ (commit &&
1846
+ (result.migrateResult?.created || result.migrateResult?.updated)))
1847
+ ) {
1848
+ log.success(
1849
+ messages.entries.imported(
1850
+ currentEnv,
1851
+ commit,
1852
+ commit
1853
+ ? (result.migrateResult?.created || 0) +
1854
+ (result.migrateResult?.updated || 0)
1855
+ : result.entriesToMigrate[currentProject].totalCount
1856
+ )
1857
+ );
1858
+ if (!commit) {
1859
+ log.raw(``);
1860
+ log.help(messages.entries.commitTip());
1861
+ }
1862
+ } else {
1863
+ log.error(messages.entries.failedImport(currentEnv), err);
1864
+ if (!result?.entriesToMigrate?.[currentProject]?.totalCount)
1865
+ log.help(messages.entries.notFound(currentEnv));
1866
+ }
1867
+ } else {
1868
+ log.warning(messages.models.noList(currentProject));
1869
+ log.help(messages.connect.tip());
1870
+ }
1871
+ };
1872
+
1791
1873
  GetNodes = async (rootPath: string, depth = 0) => {
1792
1874
  const { currentProject, log, messages } = this;
1793
1875
  const contensis = await this.ConnectContensis();
@@ -11,7 +11,7 @@ import { createRequestHandler } from '~/factories/RequestHandlerFactory';
11
11
  import { OutputOptionsConstructorArg } from '~/models/CliService';
12
12
  import { EnvContentsToAdd } from '~/models/DevService';
13
13
  import { mapCIWorkflowContent } from '~/mappers/DevInit-to-CIWorkflow';
14
- import { requestHandlerCliArgs } from '~/mappers/DevRequests-to-RequestHanderCliArgs';
14
+ import RequestHandlerArgs from '~/mappers/DevRequests-to-RequestHanderCliArgs';
15
15
  import { deployKeyRole } from '~/mappers/DevInit-to-RolePermissions';
16
16
  import { readFile, writeFile } from '~/providers/file-provider';
17
17
  import { diffFileContent } from '~/util/diff';
@@ -412,8 +412,9 @@ class ContensisDev extends ContensisRole {
412
412
  };
413
413
 
414
414
  ExecRequestHandler = async (
415
- blockIds: string[],
416
- overrideArgs: string[] = []
415
+ blockId: string[],
416
+ overrideArgs: string[] = [],
417
+ version?: string
417
418
  ) => {
418
419
  const { debug, log, messages } = this;
419
420
 
@@ -422,15 +423,45 @@ class ContensisDev extends ContensisRole {
422
423
  : log.info(messages.devrequests.launch());
423
424
 
424
425
  // Ensure request handler is available to use
425
- const requestHandler = await createRequestHandler();
426
+ const requestHandler = await createRequestHandler(version);
426
427
 
427
428
  // Generate args for request handler using CLI methods
429
+ const args = new RequestHandlerArgs(this);
428
430
  spinner?.start();
429
- const args = await requestHandlerCliArgs(this, overrideArgs);
431
+ await args.Create();
430
432
  spinner?.success();
431
433
 
434
+ // Prompt block id and dev uri to run locally (if not supplied)
435
+ const blockIdChoices = args.siteConfig?.blocks.map(block => block.id) || [];
436
+ blockIdChoices.push('none');
437
+ const defaultDeveloperUri = 'http://localhost:3000';
438
+
439
+ const { overrideBlockId, overrideUri } = blockId.length
440
+ ? {
441
+ overrideBlockId: blockId[0],
442
+ overrideUri: blockId?.[1] || defaultDeveloperUri,
443
+ }
444
+ : await inquirer.prompt([
445
+ {
446
+ type: 'list',
447
+ prefix: '🧱',
448
+ message: messages.devrequests.overrideBlock(),
449
+ name: 'overrideBlockId',
450
+ choices: blockIdChoices,
451
+ },
452
+ {
453
+ type: 'input',
454
+ prefix: '🔗',
455
+ message: messages.devrequests.overrideUri(),
456
+ name: 'overrideUri',
457
+ default: defaultDeveloperUri,
458
+ },
459
+ ]);
460
+
461
+ args.overrideBlock(overrideBlockId, overrideUri);
462
+
432
463
  // Launch request handler
433
- await requestHandler(args);
464
+ await requestHandler(args.getArgs(overrideArgs));
434
465
  };
435
466
  }
436
467
  export const devCommand = (
package/src/shell.ts CHANGED
@@ -135,6 +135,7 @@ class ContensisShell {
135
135
  availableCommands.push('login', 'list projects', 'set project');
136
136
  if (userId)
137
137
  availableCommands.push(
138
+ 'copy field',
138
139
  'create key',
139
140
  'create project',
140
141
  'create role',
@@ -306,4 +307,4 @@ process.stdin.on('data', key => {
306
307
  }
307
308
  });
308
309
 
309
- // // process.env.http_proxy = 'http://127.0.0.1:8888';
310
+ // process.env.http_proxy = 'http://127.0.0.1:8888';
@@ -0,0 +1,111 @@
1
+ export const sanitiseId = (id: string) =>
2
+ id
3
+ .split('.')
4
+ .map(part => toApiId(part, 'camelCase', true))
5
+ .join('.');
6
+
7
+ export const sanitiseIds = (arr: string[]) => arr.map(sanitiseId);
8
+
9
+ // borrowed from packages\contensis\components\app\src\utils.ts
10
+
11
+ export function isApiId(id: string, mode: 'camelCase' | 'snake-case'): boolean {
12
+ if (!id) {
13
+ return false;
14
+ }
15
+ const validChars = mode === 'camelCase' ? /[^a-zA-Z0-9]/g : /[^a-z0-9-]/g;
16
+ if (id !== id.replace(validChars, '')) {
17
+ return false;
18
+ }
19
+ if (!id.substr(0, 1).replace(/[^a-z]/g, '')) {
20
+ return false;
21
+ }
22
+ return true;
23
+ }
24
+
25
+ export function toApiId(
26
+ name: string,
27
+ mode: 'camelCase' | 'snake-case',
28
+ isId: boolean
29
+ ) {
30
+ if (!name) {
31
+ return name;
32
+ }
33
+ const validChars =
34
+ mode === 'camelCase' ? /[^a-zA-Z0-9 ]/g : /[^a-zA-Z0-9 -]/g;
35
+ let id = name.replace(validChars, '');
36
+ id = id.replace(/-/g, ' ');
37
+ id = id.trim();
38
+
39
+ const noStart = '0123456789 '.split('');
40
+ id = id
41
+ .split('')
42
+ .reduce(
43
+ (prev, char) => (prev || !noStart.includes(char) ? prev + char : prev),
44
+ ''
45
+ );
46
+ return mode === 'camelCase' ? toCamelCase(id, isId) : toSnakeCase(id);
47
+ }
48
+
49
+ function toSnakeCase(sentence: string): string {
50
+ sentence = (sentence || '').trim();
51
+ if (!sentence) {
52
+ return sentence;
53
+ }
54
+ sentence = sentence.toLowerCase();
55
+ return sentence
56
+ .split(' ')
57
+ .filter(w => !!w)
58
+ .join('-');
59
+ }
60
+
61
+ function toCamelCase(sentence: string, isId: boolean): string {
62
+ sentence = (sentence || '').trim();
63
+ if (!sentence) {
64
+ return sentence;
65
+ }
66
+ if (sentence.length < 2) {
67
+ return sentence.toLowerCase();
68
+ }
69
+ const words = sentence.split(' ');
70
+ if (isId && words.length === 1) {
71
+ return words[0].substr(0, 1).toLowerCase() + words[0].substr(1);
72
+ }
73
+ const result = words
74
+ .filter(w => !!w)
75
+ .map((w, index) =>
76
+ index === 0 ? firstWordToCamelCase(w) : wordToCamelCase(w)
77
+ )
78
+ .join('');
79
+
80
+ return result
81
+ .split('.')
82
+ .map((w, index) => (index === 0 ? w : wordToCamelCase(w)))
83
+ .join('.');
84
+ }
85
+
86
+ function firstWordToCamelCase(word: string) {
87
+ return isUpperCase(word)
88
+ ? word.toLowerCase()
89
+ : lowerCaseInitialCapitalLettersExceptLast(word);
90
+ }
91
+
92
+ function wordToCamelCase(word: string) {
93
+ return word.substr(0, 1).toUpperCase() + word.substr(1);
94
+ }
95
+
96
+ function lowerCaseInitialCapitalLettersExceptLast(value: string): string {
97
+ return value.split('').reduce((prev, char, index) => {
98
+ if (index === 0) {
99
+ char = char.toLowerCase();
100
+ } else if (isUpperCase(char)) {
101
+ if (index + 1 < value.length && isUpperCase(value.charAt(index + 1))) {
102
+ char = char.toLowerCase();
103
+ }
104
+ }
105
+ return prev + char;
106
+ }, '');
107
+ }
108
+
109
+ function isUpperCase(value: string): boolean {
110
+ return value === value.toUpperCase();
111
+ }
@@ -4,6 +4,7 @@ import { deconstructApiError } from './error';
4
4
  import { Logger, addNewLines } from './logger';
5
5
  import {
6
6
  BlockVersion,
7
+ CopyFieldResult,
7
8
  EntriesResult,
8
9
  MigrateModelsResult,
9
10
  MigrateNodesTree,
@@ -116,7 +117,7 @@ export const printBlockVersion = (
116
117
 
117
118
  export const printEntriesMigrateResult = (
118
119
  { log, messages, currentProject }: ContensisCli,
119
- migrateResult: EntriesResult,
120
+ migrateResult: EntriesResult | CopyFieldResult,
120
121
  {
121
122
  action = 'import',
122
123
  showDiff = false,
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export const LIB_VERSION = "1.1.2-beta.1";
1
+ export const LIB_VERSION = "1.1.2-beta.11";