neutrinos-cli 1.0.0

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 (57) hide show
  1. package/.configs/auth.json +5 -0
  2. package/.configs/preferences.json +5 -0
  3. package/.env +6 -0
  4. package/README.md +173 -0
  5. package/bin/cli.js +239 -0
  6. package/cli-auth/auth.js +54 -0
  7. package/cli-auth/publish.js +7 -0
  8. package/cli-auth/server.js +44 -0
  9. package/cli-auth/services/auth-utils.js +68 -0
  10. package/commands/alpha-publish.js +219 -0
  11. package/commands/attribute.js +155 -0
  12. package/commands/build.js +83 -0
  13. package/commands/deprecate.js +88 -0
  14. package/commands/dev.js +21 -0
  15. package/commands/generate.js +19 -0
  16. package/commands/new-workspace.js +142 -0
  17. package/commands/publish.js +334 -0
  18. package/commands/select-packages.mjs +36 -0
  19. package/commands/serve.js +27 -0
  20. package/package.json +34 -0
  21. package/setup.js +55 -0
  22. package/templates/assets/default-icon.png +0 -0
  23. package/templates/component/.component.ts.hbs +126 -0
  24. package/templates/component/.spec.ts.hbs +15 -0
  25. package/templates/component/.styles.ts.hbs +2 -0
  26. package/templates/module/.module.js.hbs +11 -0
  27. package/templates/plugins-server/index.js +18 -0
  28. package/templates/project/.vscode/extensions.json +6 -0
  29. package/templates/project/ATTRIBUTE.md +127 -0
  30. package/templates/project/Dockerfile +15 -0
  31. package/templates/project/helmchart/.helmignore +23 -0
  32. package/templates/project/helmchart/Chart.yaml +24 -0
  33. package/templates/project/helmchart/templates/NOTES.txt +22 -0
  34. package/templates/project/helmchart/templates/_helpers.tpl +62 -0
  35. package/templates/project/helmchart/templates/deployment.yaml +69 -0
  36. package/templates/project/helmchart/templates/ingress.yaml +62 -0
  37. package/templates/project/helmchart/templates/service.yaml +14 -0
  38. package/templates/project/helmchart/values.yaml +74 -0
  39. package/templates/project/index.html +24 -0
  40. package/templates/project/index.ts +86 -0
  41. package/templates/project/public-api.ts +0 -0
  42. package/templates/project/tsconfig.json +27 -0
  43. package/utils/attribute-utils.js +149 -0
  44. package/utils/check-valid-ws.js +21 -0
  45. package/utils/copy-utils.js +68 -0
  46. package/utils/create-client.js +23 -0
  47. package/utils/file-utils.js +43 -0
  48. package/utils/generate-component.js +101 -0
  49. package/utils/generate-module.js +51 -0
  50. package/utils/get-package-info.js +53 -0
  51. package/utils/get-packages.js +15 -0
  52. package/utils/inquirer-utils.js +49 -0
  53. package/utils/logger.js +35 -0
  54. package/utils/marketplace-api-utils.js +34 -0
  55. package/utils/path-utils.js +40 -0
  56. package/utils/prettify.js +36 -0
  57. package/utils/user-seesion-utils.js +43 -0
@@ -0,0 +1,24 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Components</title>
7
+ <style alphaGlobalStyle>
8
+ /*
9
+ Global styles with alphaGlobalStyle directive. This will be available in all components.
10
+ example render output: html`<div class="small-1">Hello World</div>`
11
+ */
12
+ .small-1 {
13
+ font-size: 12px;
14
+ }
15
+ .small-2 {
16
+ color: red;
17
+ }
18
+ </style>
19
+ </head>
20
+ <body style="padding: 1rem; box-sizing: border-box">
21
+ <div id="app"></div>
22
+ <script type="module" src="./index.ts"></script>
23
+ </body>
24
+ </html>
@@ -0,0 +1,86 @@
1
+ import * as _cs from './public-api.ts';
2
+ declare global {
3
+ interface Window {
4
+ alpha: any;
5
+ ap: any;
6
+ }
7
+ }
8
+
9
+ const setup = () => {
10
+ const style = document.createElement('style');
11
+ document.querySelector('head')?.appendChild(style);
12
+ };
13
+ /**
14
+ * Store all the component instances in globalThis.aci
15
+ * for testing purposes
16
+ */
17
+ globalThis.aci = {} as any;
18
+ const addComponent = (name: string, { inputs, outputs }: ComponentConfig) => {
19
+ const customElem = document.createElement(name) as any;
20
+ const fieldSet = document.createElement('fieldset');
21
+ const legend = document.createElement('legend');
22
+ legend.textContent = name;
23
+ fieldSet.appendChild(legend);
24
+ const key = name.slice('alpha'.length + 1);
25
+ (globalThis.aci[key] = globalThis.aci[key] || []).push(customElem);
26
+ for (let [key, val] of Object.entries(inputs || {})) {
27
+ customElem[key] = val;
28
+ const input = document.createElement('input');
29
+ input.type = 'text';
30
+ input.value = val;
31
+ input.placeholder = key;
32
+ input.addEventListener('change', (e) => {
33
+ customElem[key] = (e.target as any).value;
34
+ });
35
+ fieldSet.appendChild(input);
36
+ }
37
+ fieldSet.appendChild(customElem);
38
+ const outputEvents = outputs?.events || ['change'];
39
+ outputEvents.forEach((event) => {
40
+ customElem.addEventListener(event, (e: any) => {
41
+ console.log(`[${name}][event:${event}]`, e);
42
+ });
43
+ });
44
+ document.body.appendChild(fieldSet);
45
+ };
46
+
47
+ const components: Record<string, ComponentConfig> = (() => {
48
+ console.log(_cs);
49
+ const comps = {};
50
+ for (const [_, _class] of Object.entries(_cs)) {
51
+ const inputs = Reflect.getMetadata('AlphaAttribute', _class.prototype);
52
+ const c = Reflect.getMetadata('AlphaComponent', _class.prototype);
53
+ const selector = `${c.selector}-${c.componentVersion}`;
54
+ comps[selector] = {
55
+ inputs: inputs?.reduce((acc, { fieldMappings, defaultValue }) => {
56
+ acc[fieldMappings] = defaultValue ?? '';
57
+ return acc;
58
+ }, {}),
59
+ outputs: {
60
+ events: ['change'],
61
+ },
62
+ };
63
+ }
64
+ return comps;
65
+ })();
66
+ document.addEventListener('DOMContentLoaded', async () => {
67
+ setup();
68
+ for (let [name, config] of Object.entries(components)) {
69
+ addComponent(name, config);
70
+ }
71
+ });
72
+
73
+ interface ComponentConfig {
74
+ class?: string;
75
+ inputs?: {
76
+ disabled?: boolean;
77
+ readonly?: boolean;
78
+ value?: any;
79
+ name?: any;
80
+ id?: any;
81
+ [key: string]: any;
82
+ };
83
+ outputs?: {
84
+ events: string[];
85
+ };
86
+ }
File without changes
@@ -0,0 +1,27 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "ESNext",
5
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
6
+ "skipLibCheck": true,
7
+
8
+ /* Bundler mode */
9
+ "moduleResolution": "bundler",
10
+ "allowImportingTsExtensions": true,
11
+ "resolveJsonModule": true,
12
+ "isolatedModules": true,
13
+ "noEmit": true,
14
+
15
+ /* Decorators Support */
16
+ "experimentalDecorators": true,
17
+ "emitDecoratorMetadata": true,
18
+ "useDefineForClassFields": false,
19
+
20
+ /* Linting */
21
+ // "strict": true,
22
+ "noUnusedLocals": true,
23
+ "noUnusedParameters": true,
24
+ "noFallthroughCasesInSwitch": true
25
+ },
26
+ "include": ["packages", "index.ts"]
27
+ }
@@ -0,0 +1,149 @@
1
+ //@ts-check
2
+ import { basename, join, sep } from 'node:path';
3
+ import { MethodDeclaration, Project, SyntaxKind } from 'ts-morph';
4
+ import { done, inprogress } from './logger.js';
5
+ import { getGeneratedComponentClassName, getGeneratedComponentName } from './path-utils.js';
6
+
7
+ export const updateComponentSource = (attrMetadata, wsPath, packagePath, name) => {
8
+ inprogress('Adding the attribute to the package: ' + name);
9
+ const project = new Project({
10
+ tsConfigFilePath: join(wsPath, 'tsconfig.json'),
11
+ });
12
+
13
+ const sourceFile = project.addSourceFileAtPath(
14
+ join(packagePath, getGeneratedComponentName(basename(packagePath)) + '.ts'),
15
+ );
16
+
17
+ const fieldMappings = [];
18
+ if (attrMetadata.fieldMappings) {
19
+ if (typeof attrMetadata.fieldMappings === 'object') {
20
+ Object.keys(attrMetadata.fieldMappings).forEach((f) => {
21
+ fieldMappings.push(attrMetadata.fieldMappings[f]);
22
+ });
23
+ } else {
24
+ fieldMappings.push(attrMetadata.fieldMappings);
25
+ }
26
+ }
27
+ const classDeclaration = sourceFile.getClassOrThrow(getGeneratedComponentClassName(basename(packagePath)));
28
+ addDecorator(classDeclaration, fieldMappings, attrMetadata);
29
+ sourceFile.saveSync();
30
+ done('Attribute added successfully');
31
+ };
32
+
33
+ const addDecorator = (classDeclaration, fieldMappings, attrMetadata) => {
34
+ if (attrMetadata.type === 'ATTRIBUTE_TYPE.EVENT') {
35
+ addEventTypeDecorator(classDeclaration, attrMetadata);
36
+ } else {
37
+ addPropertyDecorator(classDeclaration, fieldMappings, attrMetadata);
38
+ }
39
+ };
40
+ const addEventTypeDecorator = (classDeclaration, attrMetadata) => {
41
+ let renderFunction = classDeclaration.getMethod('render');
42
+ if (!(renderFunction instanceof MethodDeclaration)) {
43
+ renderFunction = classDeclaration.getMethods()[0];
44
+ }
45
+ renderFunction.addDecorator({
46
+ name: 'AlphaAttribute',
47
+ arguments: [(writer) => writeDecoratorArguments(writer, attrMetadata)],
48
+ });
49
+ };
50
+ const addPropertyDecorator = (classDeclaration, fieldMappings, attrMetadata) => {
51
+ const properties = classDeclaration.getProperties();
52
+ let property = properties[0];
53
+ if (fieldMappings.length) {
54
+ fieldMappings.forEach((f) => {
55
+ const fieldMapping = f.split('.');
56
+ const propertyName = fieldMapping[0];
57
+ const prop = properties.find((p) => p.getName() === propertyName);
58
+ if (prop) {
59
+ property = prop;
60
+ return;
61
+ }
62
+ });
63
+ }
64
+ property.addDecorator({
65
+ name: 'AlphaAttribute',
66
+ arguments: [(writer) => writeDecoratorArguments(writer, attrMetadata)],
67
+ });
68
+ };
69
+
70
+ const writeDecoratorArguments = (writer, attrMetadata) => {
71
+ writer.write('{\n');
72
+ Object.entries(attrMetadata).forEach(([key, value], index, array) => {
73
+ writer.write(`\t${key}: `);
74
+ if (key === 'type' || key === 'uiType') {
75
+ writer.write(value);
76
+ } else if (typeof value === 'string') {
77
+ writer.quote(value);
78
+ } else {
79
+ writeObjectType(writer, value);
80
+ }
81
+ if (index < array.length - 1) {
82
+ writer.write(', \n');
83
+ }
84
+ });
85
+ writer.write('\n}');
86
+ };
87
+
88
+ const writeObjectType = (writer, attr) => {
89
+ if (Array.isArray(attr)) {
90
+ writer.write('[');
91
+ attr.forEach((element, index) => {
92
+ writeObjectType(writer, element);
93
+ if (index < attr.length - 1) {
94
+ writer.write(', ');
95
+ }
96
+ });
97
+ writer.write(']');
98
+ } else if (typeof attr === 'object' && attr !== null) {
99
+ writer.write('{');
100
+ Object.entries(attr).forEach(([key, val], index, array) => {
101
+ writer.write(`${key}: `);
102
+ writeObjectType(writer, val);
103
+ if (index < array.length - 1) {
104
+ writer.write(', ');
105
+ }
106
+ });
107
+ writer.write('}');
108
+ } else {
109
+ writer.quote(attr || '');
110
+ }
111
+ };
112
+
113
+ /**
114
+ * Updates the `componentVersion` property in the `@AlphaComponent` decorator.
115
+ * @param packageDir - The directory containing TypeScript files.
116
+ * @param version - The new version to set.
117
+ */
118
+ export function getAlphaComponentDecorator(packageDir) {
119
+ try {
120
+ const project = new Project();
121
+ const packageName = packageDir.split(sep).pop();
122
+ const sourceFile = project.addSourceFilesAtPaths(`${packageDir}/${packageName}.ts`) || [];
123
+
124
+ const classes = sourceFile[0]?.getClasses();
125
+
126
+ for (const classDeclaration of classes) {
127
+ const alphaComponentDecorator = classDeclaration.getDecorator('AlphaComponent');
128
+ if (!alphaComponentDecorator) {
129
+ const customElementDecorator = classDeclaration.getDecorator('customElement');
130
+ if (customElementDecorator) {
131
+ return {
132
+ label: (customElementDecorator.getArguments() || [])[0]?.getLiteralText(),
133
+ };
134
+ }
135
+ continue;
136
+ } else {
137
+ const args = alphaComponentDecorator.getArguments()[0];
138
+ if (!args || !args.isKind(SyntaxKind.ObjectLiteralExpression)) return;
139
+ return {
140
+ label: args.getProperty('label')?.getInitializer()?.getLiteralText(),
141
+ icon: args.getProperty('icon')?.getInitializer()?.getLiteralText(),
142
+ };
143
+ }
144
+ }
145
+ return null;
146
+ } catch (error) {
147
+ console.warn(`Error updating component version: ${error.message}`);
148
+ }
149
+ }
@@ -0,0 +1,21 @@
1
+ import { existsSync } from 'fs';
2
+ import { join } from 'node:path';
3
+ import { failed } from './logger.js';
4
+
5
+ export const validateWorkspace = (dir) => {
6
+ if (!dir) {
7
+ failed('Please provide a valid workspace name');
8
+ return false;
9
+ }
10
+ const pluginJson = join(dir, 'plugin.json');
11
+ if (!existsSync(pluginJson)) {
12
+ failed(`Workspace's plugin.json does not exist`);
13
+ return false;
14
+ }
15
+ const packageJson = join(dir, 'package.json');
16
+ if (!existsSync(packageJson)) {
17
+ failed(`Workspace's package.json does not exist`);
18
+ return false;
19
+ }
20
+ return true;
21
+ };
@@ -0,0 +1,68 @@
1
+ //@ts-check
2
+ import { copyFileSync, cpSync, existsSync, mkdir, mkdirSync, readdirSync } from 'node:fs';
3
+ import { basename, join } from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
5
+
6
+ const __dirname = fileURLToPath(new URL('.', import.meta.url));
7
+
8
+ export const copyDefaultAssetsToPackage = (packageDirPath) => {
9
+ copyIconDir(packageDirPath);
10
+ copyImagesDir(packageDirPath);
11
+ };
12
+
13
+ const getPackageIconDirPath = (packageDirPath) => {
14
+ return join(packageDirPath, 'assets/icon');
15
+ };
16
+
17
+ export const getPackageAssetsDirPath = (packageDirPath) => {
18
+ return join(packageDirPath, 'assets/');
19
+ };
20
+
21
+ const getPackageImagesDirPath = (packageDirPath) => {
22
+ return join(packageDirPath, 'assets/images');
23
+ };
24
+
25
+ const copyIconDir = (dir) => {
26
+ cpSync(join(__dirname, '../templates/assets'), getPackageIconDirPath(dir), {
27
+ recursive: true,
28
+ });
29
+ };
30
+ const copyImagesDir = (dir) => {
31
+ cpSync(join(__dirname, '../templates/assets'), getPackageImagesDirPath(dir), {
32
+ recursive: true,
33
+ });
34
+ };
35
+
36
+ export const copyIconToAsset = (iconPath, packageDirPath) => {
37
+ const iconAssetPath = getPackageIconDirPath(packageDirPath);
38
+ if (!existsSync(iconAssetPath)) {
39
+ mkdirSync(iconAssetPath, { recursive: true });
40
+ }
41
+ copyFileSync(iconPath, join(iconAssetPath, basename(iconPath)));
42
+ };
43
+
44
+ export const copyImagesToAsset = (imagePath, packageDirPath) => {
45
+ const imagesAssetPath = getPackageImagesDirPath(packageDirPath);
46
+ if (!existsSync(imagesAssetPath)) {
47
+ mkdir(imagesAssetPath, { recursive: true }, (err) => {
48
+ if (err) throw err;
49
+ });
50
+ }
51
+ copyFileSync(imagePath, join(imagesAssetPath, basename(imagePath)));
52
+ };
53
+
54
+ export const getPackageIcon = (packageDirPath) => {
55
+ const pkgIconDirPath = getPackageIconDirPath(packageDirPath);
56
+ const icon = existsSync(pkgIconDirPath) ? readdirSync(pkgIconDirPath) : [];
57
+ if (icon && icon.length) {
58
+ return join(pkgIconDirPath, icon[0]);
59
+ }
60
+ return null;
61
+ };
62
+
63
+ export const getPackageImages = (packageDirPath) => {
64
+ const pkgImageDirPath = getPackageImagesDirPath(packageDirPath);
65
+ return ((existsSync(pkgImageDirPath) ? readdirSync(pkgImageDirPath) : []) || []).map((img) => {
66
+ return join(pkgImageDirPath, img);
67
+ });
68
+ };
@@ -0,0 +1,23 @@
1
+ //@ts-check
2
+ import { env } from 'node:process';
3
+ import { Issuer } from 'openid-client';
4
+ export const createClient = async () => {
5
+ if (!env.ISSUER_URL) {
6
+ console.error('Issuer URL not found');
7
+ return;
8
+ }
9
+ const issuer = await Issuer.discover(env.ISSUER_URL);
10
+ if (!issuer) {
11
+ console.error('Issuer not found');
12
+ return;
13
+ }
14
+ if (!env.IDS_CLIENT_ID || !env.IDS_CLIENT_SECRET) {
15
+ console.error('Client ID or Client Secret not found');
16
+ return;
17
+ }
18
+ const client = new issuer.Client({
19
+ client_id: env.IDS_CLIENT_ID,
20
+ client_secret: env.IDS_CLIENT_SECRET,
21
+ });
22
+ return client;
23
+ };
@@ -0,0 +1,43 @@
1
+ //@ts-check
2
+ import AdmZip from 'adm-zip';
3
+ import { execSync } from 'node:child_process';
4
+ import { createReadStream, existsSync, readFileSync, unlink, writeFileSync } from 'node:fs';
5
+ import { join } from 'node:path';
6
+ import { copyIconToAsset } from './copy-utils.js';
7
+ import { failed } from './logger.js';
8
+
9
+ export const createZipArchive = async (directoryPath, packageName, wsPath, isModule) => {
10
+ const buildCommand = `alpha build plugins ${packageName} ${isModule ? '--module' : ''}`;
11
+ execSync(buildCommand, {
12
+ cwd: wsPath,
13
+ stdio: 'inherit',
14
+ });
15
+
16
+ const zip = AdmZip();
17
+ zip.addLocalFolder(directoryPath);
18
+ const zipBuffer = zip.toBuffer();
19
+
20
+ const zipFilePath = join(directoryPath, `${packageName.toLowerCase()}.zip`);
21
+ writeFileSync(zipFilePath, zipBuffer);
22
+
23
+ const zipStream = createReadStream(zipFilePath);
24
+ zipStream.on('close', () => unlink(zipFilePath, () => new Error('Error deleting zip file')));
25
+
26
+ return zipStream;
27
+ };
28
+
29
+ export function getPackageJson(packageJsonPath) {
30
+ return JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
31
+ }
32
+
33
+ export function getIconStream(iconPath, packageDirPath) {
34
+ if (existsSync(iconPath)) {
35
+ copyIconToAsset(iconPath, packageDirPath);
36
+ return getFileReadableStream(iconPath);
37
+ }
38
+ return null;
39
+ }
40
+
41
+ export function getFileReadableStream(filePath) {
42
+ return existsSync(filePath) ? createReadStream(filePath) : failed("Invalid file path or file doesn't exist");
43
+ }
@@ -0,0 +1,101 @@
1
+ //@ts-check
2
+ import { pascalCase, sentenceCase } from 'change-case';
3
+ import { bold } from 'colorette';
4
+ import handlebars from 'handlebars';
5
+ import { execSync } from 'node:child_process';
6
+ // prettier-ignore
7
+ import { existsSync,mkdirSync,readFileSync,rmSync,writeFileSync } from 'node:fs';
8
+ import { appendFile, writeFile } from 'node:fs/promises';
9
+ import { join } from 'node:path';
10
+ import { copyDefaultAssetsToPackage } from './copy-utils.js';
11
+ import { done, failed, inprogress } from './logger.js';
12
+ import { componentTemplatesPath, getGeneratedComponentName } from './path-utils.js';
13
+ import { prettify } from './prettify.js';
14
+
15
+ export const generateComponentPackageInWorkspace = async (wsPath, name, description) => {
16
+ const componentDir = join(wsPath, 'packages', name);
17
+ if (existsSync(componentDir)) {
18
+ failed(`Component ${componentDir} already exists`, new Error());
19
+ process.exit(1);
20
+ }
21
+ try {
22
+ inprogress(`Generating component package with name: ${bold(name)}`);
23
+ execSync(`npm init -y -w packages/${name}`);
24
+ done(`Initialized component project in workspace: ${bold(name)}`);
25
+ await createComponentFiles(name, componentDir, wsPath);
26
+ copyDefaultAssetsToPackage(componentDir);
27
+ modPkgJSon(componentDir, description);
28
+ } catch (err) {
29
+ failed(`Failed to generate component package: ${name}`, err);
30
+ cleanUp(componentDir);
31
+ }
32
+ };
33
+
34
+ const modPkgJSon = (componentDir, description) => {
35
+ const pkgJsonPath = join(componentDir, 'package.json');
36
+ const pkg = JSON.parse(readFileSync(pkgJsonPath, 'utf-8'));
37
+ pkg.alpha = {
38
+ component: true,
39
+ description,
40
+ };
41
+ writeFileSync(pkgJsonPath, JSON.stringify(pkg, null, 2));
42
+ };
43
+
44
+ const createTs = (config) => {
45
+ const template = handlebars.compile(readFileSync(join(componentTemplatesPath(), '.component.ts.hbs'), 'utf-8'));
46
+ return template(config);
47
+ };
48
+
49
+ const createStyles = (config) => {
50
+ const template = handlebars.compile(readFileSync(join(componentTemplatesPath(), '.styles.ts.hbs'), 'utf-8'));
51
+ return template(config);
52
+ };
53
+
54
+ const createTest = (config) => {
55
+ const template = handlebars.compile(readFileSync(join(componentTemplatesPath(), '.test.ts.hbs'), 'utf-8'));
56
+ return template(config);
57
+ };
58
+
59
+ const appendToPublicAPIExports = (config) => {
60
+ const { componentSelector, componentDirName } = config;
61
+ return `export * from './packages/${componentDirName}/${componentSelector}';`;
62
+ };
63
+
64
+ const createComponentFiles = async (name, componentDirPath, wsPath) => {
65
+ const pluginJson = JSON.parse(readFileSync(join(wsPath, 'plugin.json'), 'utf-8'));
66
+ const componentSelector = getGeneratedComponentName(name);
67
+ const componentClassName = pascalCase(name);
68
+ const config = {
69
+ componentSelectorPrefix: pluginJson.components?.selectorPrefix || 'comp',
70
+ componentDirName: name,
71
+ componentSelector,
72
+ componentClassName,
73
+ componentDirPath,
74
+ componentLabel: sentenceCase(name),
75
+ };
76
+ mkdirSync(componentDirPath, { recursive: true });
77
+ await Promise.all([
78
+ writeFile(join(componentDirPath, `${componentSelector}.ts`), createTs(config), 'utf-8'),
79
+ writeFile(
80
+ join(componentDirPath, `${componentSelector}.styles.ts`),
81
+ await prettify(createStyles(config), 'typescript'),
82
+ 'utf-8',
83
+ ),
84
+ ]);
85
+ const publicAPIPath = join(wsPath, './public-api.ts');
86
+ const publicAPIContent = readFileSync(publicAPIPath, 'utf-8');
87
+ const appendingContent = await prettify(appendToPublicAPIExports(config), 'typescript');
88
+ try {
89
+ await appendFile(publicAPIPath, appendingContent, 'utf-8');
90
+ } catch (err) {
91
+ failed(`Failed to update public-api.ts`, err);
92
+ writeFileSync(publicAPIPath, publicAPIContent);
93
+ throw err;
94
+ }
95
+ };
96
+
97
+ const cleanUp = (dir) => {
98
+ inprogress('Cleaning up...');
99
+ rmSync(dir, { recursive: true });
100
+ done('Cleaned up workspace');
101
+ };
@@ -0,0 +1,51 @@
1
+ //@ts-check
2
+ import { kebabCase, pascalCase } from 'change-case';
3
+ import { bold } from 'colorette';
4
+ import handlebars from 'handlebars';
5
+ import { execSync } from 'node:child_process';
6
+ import { existsSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
7
+ import { join } from 'node:path';
8
+ import { exit } from 'node:process';
9
+ import { copyDefaultAssetsToPackage } from './copy-utils.js';
10
+ import { done, failed, inprogress } from './logger.js';
11
+ import { modulesTemplatesPath, pluginJsonPath } from './path-utils.js';
12
+ import { prettify } from './prettify.js';
13
+
14
+ export const generateModulePackageInWorkspace = async (wsPath, name, description) => {
15
+ const dir = join(wsPath, 'packages', name);
16
+ if (existsSync(dir)) {
17
+ failed(`Module ${dir} already exists`);
18
+ exit(1);
19
+ }
20
+ try {
21
+ inprogress(`Generating component package with name: ${bold(name)}`);
22
+ execSync(`npm init -y -w packages/${name}`);
23
+ modPkgJSon(dir, description);
24
+ await createModuleFiles(name, dir, wsPath);
25
+ copyDefaultAssetsToPackage(dir);
26
+ done(`Initialized module project in workspace: ${bold(name)}`);
27
+ } catch (err) {
28
+ failed(`Failed to generate module package: ${name}`, err);
29
+ rmSync(dir, { recursive: true });
30
+ }
31
+ };
32
+
33
+ const modPkgJSon = (dir, description) => {
34
+ const pkgJsonPath = join(dir, 'package.json');
35
+ const pkg = JSON.parse(readFileSync(pkgJsonPath, 'utf-8'));
36
+ pkg.alpha = {
37
+ module: true,
38
+ description,
39
+ };
40
+ writeFileSync(pkgJsonPath, JSON.stringify(pkg, null, 2));
41
+ };
42
+
43
+ const createModuleFiles = async (name, moduleDirPath, wsPath) => {
44
+ const template = handlebars.compile(readFileSync(join(modulesTemplatesPath(), '.module.js.hbs'), 'utf-8'));
45
+ const pluginJson = JSON.parse(readFileSync(pluginJsonPath(wsPath), 'utf-8'));
46
+ const content = template({
47
+ pluginClassName: pascalCase(name),
48
+ pluginId: pluginJson.modules.idPrefix + kebabCase(name),
49
+ });
50
+ writeFileSync(join(moduleDirPath, 'index.js'), await prettify(content, 'typescript'));
51
+ };
@@ -0,0 +1,53 @@
1
+ //@ts-check
2
+ import { existsSync, readFileSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ import { getPackages } from './get-packages.js';
5
+ import { inquiry } from './inquirer-utils.js';
6
+ import { failed } from './logger.js';
7
+
8
+ export const getPackageMetadata = async (wsPath, packageName, pkgType = '') => {
9
+ const packages = getPackages(wsPath);
10
+
11
+ if (!packages.length) {
12
+ failed('No packages found in the workspace');
13
+ }
14
+ let componentDirPath = '';
15
+
16
+ if (!packageName) {
17
+ const question = {
18
+ type: 'list',
19
+ name: 'value',
20
+ choices: packages
21
+ .map((p) => {
22
+ const pkgJson = JSON.parse(readFileSync(join(p, 'package.json'), 'utf-8'));
23
+ if (!pkgType || pkgJson.alpha[pkgType]) {
24
+ return {
25
+ name: `${p} (${pkgJson.name})`,
26
+ value: {
27
+ path: p,
28
+ componentName: pkgJson.name,
29
+ },
30
+ };
31
+ }
32
+ })
33
+ .filter(Boolean),
34
+ message: 'Choose the Package Name to Publish :',
35
+ };
36
+ const { componentName, path } = (await inquiry(question)).value;
37
+ packageName = componentName;
38
+ componentDirPath = path;
39
+ } else {
40
+ componentDirPath =
41
+ packages.find((v) => JSON.parse(readFileSync(join(v, 'package.json'), 'utf-8')).name === packageName) || '';
42
+ }
43
+
44
+ const componentExist = existsSync(componentDirPath);
45
+ if (!componentExist) {
46
+ throw new Error(packageName + " doesn't exist");
47
+ }
48
+
49
+ return {
50
+ packageName,
51
+ componentDirPath,
52
+ };
53
+ };
@@ -0,0 +1,15 @@
1
+ //@ts-check
2
+ import { existsSync, globSync, readFileSync } from 'fs';
3
+ import { join } from 'path';
4
+
5
+ export const getPackages = (wsPath) => {
6
+ const packagesDir = JSON.parse(readFileSync(join(wsPath, 'package.json'), 'utf-8')).workspaces;
7
+ const packageNames = globSync(packagesDir, { cwd: wsPath });
8
+ return (
9
+ packageNames
10
+ .map((name) => join(wsPath, name))
11
+ .filter((p) => {
12
+ return existsSync(join(p, 'package.json'));
13
+ }) || []
14
+ );
15
+ };