@servicetitan/startup 22.1.0 → 22.2.1

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 (44) hide show
  1. package/dist/cli/commands/index.d.ts +2 -0
  2. package/dist/cli/commands/index.d.ts.map +1 -1
  3. package/dist/cli/commands/index.js +2 -0
  4. package/dist/cli/commands/index.js.map +1 -1
  5. package/dist/cli/commands/lint.d.ts +3 -0
  6. package/dist/cli/commands/lint.d.ts.map +1 -1
  7. package/dist/cli/commands/lint.js +19 -0
  8. package/dist/cli/commands/lint.js.map +1 -1
  9. package/dist/cli/commands/mfe-publish.d.ts +36 -0
  10. package/dist/cli/commands/mfe-publish.d.ts.map +1 -0
  11. package/dist/cli/commands/mfe-publish.js +268 -0
  12. package/dist/cli/commands/mfe-publish.js.map +1 -0
  13. package/dist/cli/commands/styles-check.d.ts +5 -0
  14. package/dist/cli/commands/styles-check.d.ts.map +1 -0
  15. package/dist/cli/commands/styles-check.js +124 -0
  16. package/dist/cli/commands/styles-check.js.map +1 -0
  17. package/dist/cli/index.js +8 -0
  18. package/dist/cli/index.js.map +1 -1
  19. package/dist/cli/utils/cli-git.d.ts +3 -0
  20. package/dist/cli/utils/cli-git.d.ts.map +1 -0
  21. package/dist/cli/utils/cli-git.js +13 -0
  22. package/dist/cli/utils/cli-git.js.map +1 -0
  23. package/dist/cli/utils/cli-npm.d.ts +7 -0
  24. package/dist/cli/utils/cli-npm.d.ts.map +1 -0
  25. package/dist/cli/utils/cli-npm.js +55 -0
  26. package/dist/cli/utils/cli-npm.js.map +1 -0
  27. package/dist/cli/utils/cli-os.d.ts +4 -0
  28. package/dist/cli/utils/cli-os.d.ts.map +1 -0
  29. package/dist/cli/utils/cli-os.js +56 -0
  30. package/dist/cli/utils/cli-os.js.map +1 -0
  31. package/dist/utils/get-configuration.d.ts +2 -0
  32. package/dist/utils/get-configuration.d.ts.map +1 -1
  33. package/dist/utils/get-configuration.js +10 -1
  34. package/dist/utils/get-configuration.js.map +1 -1
  35. package/package.json +9 -9
  36. package/src/cli/commands/index.ts +2 -0
  37. package/src/cli/commands/lint.ts +19 -0
  38. package/src/cli/commands/mfe-publish.ts +317 -0
  39. package/src/cli/commands/styles-check.ts +141 -0
  40. package/src/cli/index.ts +16 -0
  41. package/src/cli/utils/cli-git.ts +9 -0
  42. package/src/cli/utils/cli-npm.ts +55 -0
  43. package/src/cli/utils/cli-os.ts +76 -0
  44. package/src/utils/get-configuration.ts +11 -0
@@ -0,0 +1,141 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import process from 'process';
4
+ import {
5
+ getFolders,
6
+ isBundle,
7
+ isLegacy,
8
+ isStyleCheckDisabled,
9
+ isWebComponent,
10
+ log,
11
+ } from '../../utils';
12
+ import { Command } from './index';
13
+
14
+ interface FileInfo {
15
+ path: string;
16
+ relativePath: string;
17
+ }
18
+
19
+ const styleCheckError = [
20
+ '!!!!!!!!!!!!! STYLE CHECK ERROR !!!!!!!!!!!!!',
21
+ 'Style check failed with following errors:',
22
+ ];
23
+ const designSystem = 'design-system.css';
24
+
25
+ enum PackageType {
26
+ App = 'app',
27
+ WebComponent = 'web_component',
28
+ }
29
+
30
+ function readDir(startPath: string, filter: string[]): string[] {
31
+ let out: string[] = [];
32
+
33
+ if (!fs.existsSync(startPath)) {
34
+ return out;
35
+ }
36
+
37
+ const files = fs.readdirSync(startPath);
38
+ for (const file of files) {
39
+ const filename = path.join(startPath, file);
40
+ const stat = fs.lstatSync(filename);
41
+
42
+ if (stat.isDirectory()) {
43
+ out = [...out, ...readDir(filename, filter)];
44
+ } else if (filter.some(f => filename.endsWith(f))) {
45
+ out.push(filename);
46
+ }
47
+ }
48
+
49
+ return out;
50
+ }
51
+
52
+ const findStyleFiles = (basePath: string, sourceFolder: string): FileInfo[] => {
53
+ const sourcePath = path.join(basePath, sourceFolder);
54
+ const files = readDir(sourcePath, ['.css', '.less']);
55
+
56
+ return files.map(f => ({
57
+ path: f,
58
+ relativePath: f.replace(sourcePath, '').substring(1),
59
+ }));
60
+ };
61
+
62
+ const checkStyleFiles = (files: FileInfo[], packageType: PackageType): string[] | undefined => {
63
+ const errors = [];
64
+ const patterns = [
65
+ "@import '~@servicetitan/tokens/core/tokens.css';",
66
+ "@import '~@servicetitan/anvil-fonts/dist/css/anvil-fonts.css';",
67
+ "@import '~@servicetitan/design-system/dist/system.min.css';",
68
+ ];
69
+
70
+ for (const file of files) {
71
+ if (
72
+ [PackageType.App, PackageType.WebComponent].includes(packageType) &&
73
+ file.relativePath === designSystem
74
+ ) {
75
+ continue;
76
+ }
77
+
78
+ const content = fs.readFileSync(file.path);
79
+
80
+ for (const pattern of patterns) {
81
+ if (content.includes(pattern)) {
82
+ errors.push(`file ${file.relativePath} contains link to "${pattern}"`);
83
+ }
84
+ }
85
+ }
86
+
87
+ return errors.length ? errors : undefined;
88
+ };
89
+
90
+ const checkErrors = (errors: string[] | undefined) => {
91
+ if (!errors) {
92
+ log.info('style check: OK');
93
+ } else {
94
+ log.error([...styleCheckError, ...errors].join('\n'));
95
+ throw new Error('style check error, please check logs above');
96
+ }
97
+ };
98
+
99
+ function checkStylesLib(_files: FileInfo[]) {
100
+ /* ToDo: add checks for libraries */
101
+ }
102
+
103
+ function checkStylesApp(files: FileInfo[]) {
104
+ if (!files.some(f => f.relativePath === designSystem)) {
105
+ log.warning(
106
+ "application doesn't have design-system.css. Please check https://docs.st.dev/docs/frontend/micro-frontends#host-configuration"
107
+ );
108
+ }
109
+
110
+ checkErrors(checkStyleFiles(files, PackageType.App));
111
+ }
112
+
113
+ function checkStylesWebComponent(files: FileInfo[]) {
114
+ checkErrors(checkStyleFiles(files, PackageType.WebComponent));
115
+ }
116
+
117
+ export class StylesCheck implements Command {
118
+ // eslint-disable-next-line @typescript-eslint/require-await
119
+ async execute() {
120
+ if (isLegacy()) {
121
+ return;
122
+ }
123
+
124
+ if (isStyleCheckDisabled()) {
125
+ log.info('style check is disabled');
126
+
127
+ return;
128
+ }
129
+
130
+ const projectFolders = getFolders();
131
+ const files = findStyleFiles(process.cwd(), projectFolders.source);
132
+
133
+ if (!isBundle()) {
134
+ checkStylesLib(files);
135
+ } else if (isWebComponent()) {
136
+ checkStylesWebComponent(files);
137
+ } else {
138
+ checkStylesApp(files);
139
+ }
140
+ }
141
+ }
package/src/cli/index.ts CHANGED
@@ -10,6 +10,10 @@ import {
10
10
  BundlePackage,
11
11
  Lint,
12
12
  Tests,
13
+ StylesCheck,
14
+ MFEPackageClean,
15
+ MFEPackagePublish,
16
+ MFEPublish,
13
17
  } from './commands';
14
18
 
15
19
  interface Newable<T> {
@@ -39,6 +43,18 @@ function getCommand(name: string): Newable<Command> {
39
43
  case 'test':
40
44
  return Tests;
41
45
 
46
+ case 'styles-check':
47
+ return StylesCheck;
48
+
49
+ case 'mfe-publish':
50
+ return MFEPublish;
51
+
52
+ case 'mfe-package-publish':
53
+ return MFEPackagePublish;
54
+
55
+ case 'mfe-package-clean':
56
+ return MFEPackageClean;
57
+
42
58
  default:
43
59
  log.error(`${name}: command not found!`);
44
60
  process.exit(127);
@@ -0,0 +1,9 @@
1
+ import { runCommandOutput } from './cli-os';
2
+
3
+ export const gitGetBranch = (): string => {
4
+ return runCommandOutput('git rev-parse --abbrev-ref HEAD').trim();
5
+ };
6
+
7
+ export const gitGetCommitHash = (): string => {
8
+ return runCommandOutput('git rev-parse --short HEAD').trim();
9
+ };
@@ -0,0 +1,55 @@
1
+ import { runCommand, runCommandOutput } from './cli-os';
2
+
3
+ export const npmGetPackageVersions = (registry: string, packageName: string): string[] => {
4
+ try {
5
+ const v = runCommandOutput(
6
+ `npm show ${packageName} versions --registry ${registry} --json`,
7
+ { timeout: 10000 }
8
+ );
9
+
10
+ return JSON.parse(v);
11
+ } catch {
12
+ return [];
13
+ }
14
+ };
15
+
16
+ export const npmGetPackageVersionDates = (
17
+ registry: string,
18
+ packageName: string
19
+ ): [string, Date][] => {
20
+ try {
21
+ const v = runCommandOutput(`npm view ${packageName} time --registry ${registry} --json`, {
22
+ timeout: 10000,
23
+ });
24
+ const map = JSON.parse(v);
25
+
26
+ return Object.keys(map).reduce(
27
+ (out, version) => [...out, [version, new Date(map[version])]],
28
+ []
29
+ );
30
+ } catch {
31
+ return [];
32
+ }
33
+ };
34
+
35
+ export const npmUnpublish = async (
36
+ registry: string,
37
+ packageName: string,
38
+ packageVersion: string
39
+ ) => {
40
+ await runCommand(`npm unpublish ${packageName}@${packageVersion} --registry ${registry}`, {
41
+ timeout: 10000,
42
+ });
43
+ };
44
+
45
+ export const npmPublishDry = async () => {
46
+ await runCommand('npm publish --dry-run');
47
+ };
48
+
49
+ export const npmPublish = async (tag?: string) => {
50
+ await runCommand(['npm publish', !!tag && `--tag ${tag}`]);
51
+ };
52
+
53
+ export const npmPackageSet = async (key: string, value: string) => {
54
+ await runCommand(`npm pkg set ${key}=${value}`);
55
+ };
@@ -0,0 +1,76 @@
1
+ import {
2
+ execSync,
3
+ ExecSyncOptionsWithBufferEncoding,
4
+ spawn,
5
+ SpawnOptionsWithoutStdio,
6
+ } from 'child_process';
7
+ import { log } from '../../utils';
8
+
9
+ export const runCommand = (
10
+ command: string | (string | false)[],
11
+ opts?: SpawnOptionsWithoutStdio
12
+ ): Promise<void> => {
13
+ return new Promise((resolve, reject) => {
14
+ const commandArray: string[] = Array.isArray(command)
15
+ ? command
16
+ .filter(c => !!c)
17
+ .map(c => c.toString())
18
+ .join(' ')
19
+ .split(' ')
20
+ : command.split(' ');
21
+ const fullCommand = commandArray.join(' ');
22
+
23
+ const commandName = commandArray.shift();
24
+
25
+ if (!commandName) {
26
+ reject();
27
+
28
+ return;
29
+ }
30
+
31
+ log.info(`run command ${fullCommand}`);
32
+
33
+ const proc = spawn(commandName, commandArray, opts);
34
+
35
+ proc.stdout.pipe(process.stdout);
36
+ proc.stderr.pipe(process.stderr);
37
+
38
+ proc.on('exit', function (code: any) {
39
+ log.info(`command finished with code ${code}`, fullCommand);
40
+
41
+ if (code) {
42
+ reject();
43
+ } else {
44
+ resolve();
45
+ }
46
+ });
47
+ });
48
+ };
49
+
50
+ export const runCommandOutput = (
51
+ command: string | (string | false)[],
52
+ options?: ExecSyncOptionsWithBufferEncoding
53
+ ): string => {
54
+ const commandArray: string[] = Array.isArray(command)
55
+ ? command
56
+ .filter(c => !!c)
57
+ .map(c => c.toString())
58
+ .join(' ')
59
+ .split(' ')
60
+ : command.split(' ');
61
+ const fullCommand = commandArray.join(' ');
62
+
63
+ const commandName = commandArray.shift();
64
+
65
+ if (!commandName) {
66
+ throw new Error();
67
+ }
68
+
69
+ log.info(`run command ${fullCommand}`);
70
+
71
+ const result = execSync(fullCommand, options).toString();
72
+
73
+ log.info('command finished', result);
74
+
75
+ return result;
76
+ };
@@ -19,6 +19,7 @@ export interface WebpackConfiguration
19
19
  > {
20
20
  'custom-style-rules'?: boolean;
21
21
  'expose-shared-dependencies'?: boolean;
22
+ 'disable-style-check'?: boolean;
22
23
  'proxy'?: WebpackDevServerConfiguration['proxy'] | string;
23
24
  }
24
25
 
@@ -122,3 +123,13 @@ export function getStylelintConfiguration() {
122
123
  export function getJestConfiguration() {
123
124
  return getConfiguration().test ?? {};
124
125
  }
126
+
127
+ export function isStyleCheckDisabled() {
128
+ const configuration = getConfiguration();
129
+
130
+ if (typeof configuration.webpack !== 'object') {
131
+ return false;
132
+ }
133
+
134
+ return configuration.webpack?.['disable-style-check'] === true;
135
+ }