@teambit/generator 1.0.8 → 1.0.9
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/.bit-capsule-ready +0 -0
- package/component-generator.ts +271 -0
- package/component-template.ts +122 -0
- package/create.cmd.ts +88 -0
- package/dist/generator.composition.d.ts +2 -2
- package/dist/generator.graphql.js +2 -2
- package/dist/generator.graphql.js.map +1 -1
- package/dist/generator.main.runtime.js +5 -4
- package/dist/generator.main.runtime.js.map +1 -1
- package/dist/templates/basic/basic.starter.js +8 -4
- package/dist/templates/basic/basic.starter.js.map +1 -1
- package/dist/templates/basic/template/files/workspace-config.js +4 -4
- package/dist/templates/basic/template/files/workspace-config.js.map +1 -1
- package/dist/templates/starter/files/starter.js +4 -0
- package/dist/templates/starter/files/starter.js.map +1 -1
- package/dist/templates/starter/files/workspace-config-tpl.js +19 -9
- package/dist/templates/starter/files/workspace-config-tpl.js.map +1 -1
- package/dist/templates/starter-standalone/files/starter.js +9 -0
- package/dist/templates/starter-standalone/files/starter.js.map +1 -1
- package/dist/templates/starter-standalone/files/workspace-config-tpl.js +19 -8
- package/dist/templates/starter-standalone/files/workspace-config-tpl.js.map +1 -1
- package/generator-env-type.ts +14 -0
- package/generator.aspect.ts +5 -0
- package/generator.graphql.ts +62 -0
- package/generator.main.runtime.ts +577 -0
- package/index.ts +14 -0
- package/new.cmd.ts +114 -0
- package/package-tar/teambit-generator-1.0.9.tgz +0 -0
- package/package.json +22 -23
- package/schema.json +10304 -0
- package/starter-list.ts +21 -0
- package/starter.plugin.ts +16 -0
- package/teambit_generator_generator-preview.js +11 -0
- package/template-list.ts +21 -0
- package/templates/basic/basic.starter.ts +10 -5
- package/templates/basic/template/files/workspace-config.ts +2 -2
- package/templates/starter/files/starter.ts +5 -1
- package/templates/starter/files/workspace-config-tpl.ts +20 -10
- package/templates/starter-standalone/files/starter.ts +10 -1
- package/templates/starter-standalone/files/workspace-config-tpl.ts +20 -9
- package/templates.cmd.ts +55 -0
- package/types.ts +3 -0
- package/workspace-generator.ts +205 -0
- package/workspace-template.ts +145 -0
- package/dist/preview-1695698249502.js +0 -7
- package/tsconfig.json +0 -40
- package/types/asset.d.ts +0 -29
- package/types/style.d.ts +0 -42
package/starter-list.ts
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
import { EnvContext, EnvHandler } from '@teambit/envs';
|
2
|
+
import { WorkspaceTemplate } from './workspace-template';
|
3
|
+
|
4
|
+
export type StarterListOptions = {
|
5
|
+
name?: string;
|
6
|
+
};
|
7
|
+
|
8
|
+
export class StarterList {
|
9
|
+
constructor(readonly name: string, private starters: EnvHandler<WorkspaceTemplate>[], private context: EnvContext) {}
|
10
|
+
|
11
|
+
compute(): WorkspaceTemplate[] {
|
12
|
+
return this.starters.map((starter) => starter(this.context));
|
13
|
+
}
|
14
|
+
|
15
|
+
static from(starters: EnvHandler<WorkspaceTemplate>[], options: StarterListOptions = {}) {
|
16
|
+
return (context: EnvContext) => {
|
17
|
+
const name = options.name || 'starter-list';
|
18
|
+
return new StarterList(name, starters, context);
|
19
|
+
};
|
20
|
+
}
|
21
|
+
}
|
@@ -0,0 +1,16 @@
|
|
1
|
+
import { PluginDefinition } from '@teambit/aspect-loader';
|
2
|
+
import { MainRuntime } from '@teambit/cli';
|
3
|
+
import { GeneratorMain } from './generator.main.runtime';
|
4
|
+
|
5
|
+
export class StarterPlugin implements PluginDefinition {
|
6
|
+
constructor(private generator: GeneratorMain) {}
|
7
|
+
|
8
|
+
pattern = '*.starter.*';
|
9
|
+
|
10
|
+
runtimes = [MainRuntime.name];
|
11
|
+
|
12
|
+
register(object: any) {
|
13
|
+
const templates = Array.isArray(object) ? object : [object];
|
14
|
+
return this.generator.registerWorkspaceTemplate(templates);
|
15
|
+
}
|
16
|
+
}
|
@@ -0,0 +1,11 @@
|
|
1
|
+
(function(root,factory){typeof exports=="object"&&typeof module=="object"?module.exports=factory():typeof define=="function"&&define.amd?define([],factory):typeof exports=="object"?exports["teambit.generator/generator-preview"]=factory():root["teambit.generator/generator-preview"]=factory()})(self,()=>(()=>{"use strict";var __webpack_modules__={493:(__unused_webpack_module,exports2,__webpack_require__2)=>{var __bit_component={id:"teambit.generator/aspect-docs/generator@0.0.165",homepage:"https://bit.cloud/teambit/generator/aspect-docs/generator",exported:!0};Object.defineProperty(exports2,"__esModule",{value:!0}),exports2.default=MDXContent;var _react=_interopRequireDefault(__webpack_require__2(363)),_react2=__webpack_require__2(40),_excluded=["components"];function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}_interopRequireDefault.__bit_component=__bit_component;function _extends(){return _extends=Object.assign?Object.assign.bind():function(target){for(var i=1;i<arguments.length;i++){var source=arguments[i];for(var key in source)Object.prototype.hasOwnProperty.call(source,key)&&(target[key]=source[key])}return target},_extends.apply(this,arguments)}_extends.__bit_component=__bit_component;function _objectWithoutProperties(source,excluded){if(source==null)return{};var target=_objectWithoutPropertiesLoose(source,excluded),key,i;if(Object.getOwnPropertySymbols){var sourceSymbolKeys=Object.getOwnPropertySymbols(source);for(i=0;i<sourceSymbolKeys.length;i++)key=sourceSymbolKeys[i],!(excluded.indexOf(key)>=0)&&(!Object.prototype.propertyIsEnumerable.call(source,key)||(target[key]=source[key]))}return target}_objectWithoutProperties.__bit_component=__bit_component;function _objectWithoutPropertiesLoose(source,excluded){if(source==null)return{};var target={},sourceKeys=Object.keys(source),key,i;for(i=0;i<sourceKeys.length;i++)key=sourceKeys[i],!(excluded.indexOf(key)>=0)&&(target[key]=source[key]);return target}_objectWithoutPropertiesLoose.__bit_component=__bit_component;var layoutProps={},MDXLayout="wrapper";function MDXContent(_ref){var components=_ref.components,props=_objectWithoutProperties(_ref,_excluded);return(0,_react2.mdx)(MDXLayout,_extends({},layoutProps,props,{components,mdxType:"MDXLayout"}),(0,_react2.mdx)("p",null,"Generator extension enable generating new components by pre-defined templates"),(0,_react2.mdx)("h3",null,"Component location"),(0,_react2.mdx)("p",null,"Component location in the workspace directory tree is defined with the ",(0,_react2.mdx)("inlineCode",{parentName:"p"},"bit create")," command (see below). For example, a component named ",(0,_react2.mdx)("inlineCode",{parentName:"p"},"ShoppingCart")," created in the ",(0,_react2.mdx)("inlineCode",{parentName:"p"},"acme.shopper")," and the namespace ",(0,_react2.mdx)("inlineCode",{parentName:"p"},"ui")," will be generated in the following directory:"),(0,_react2.mdx)("pre",null,(0,_react2.mdx)("code",{parentName:"pre"},`acme.shopper/ui/shopping-cart
|
2
|
+
`)),(0,_react2.mdx)("h3",null,"Component name"),(0,_react2.mdx)("p",null,"When using templates Bit will use CamelCasing for passing the component-name to the template, but generated file structure should be in kebab-case, for better cross-operating-system compatibility of the component."),(0,_react2.mdx)("h3",null,"Automatically ",(0,_react2.mdx)("inlineCode",{parentName:"h3"},"add")," component"),(0,_react2.mdx)("p",null,"Bit should automatically register the new component to the ",(0,_react2.mdx)("inlineCode",{parentName:"p"},".bitmap")," file with a symmetrical name to the component-location in the workspace."),(0,_react2.mdx)("h2",null,"Register a template"),(0,_react2.mdx)("p",null,"Any aspect (include envs) can register templates. Each template should have a name and a list of files. Each file has a relative-path to the component-dir and template content. See the ",(0,_react2.mdx)("inlineCode",{parentName:"p"},"component-template.ts")," file for more info about the exact API."),(0,_react2.mdx)("ul",null,(0,_react2.mdx)("li",{parentName:"ul"},"Component name should be available as a param for the file-content-template."),(0,_react2.mdx)("li",{parentName:"ul"},"TBD: An environment must have a default template (if not set, use first template in array?).")),(0,_react2.mdx)("p",null,"To register a template, use the Generator API: ",(0,_react2.mdx)("inlineCode",{parentName:"p"},"registerComponentTemplate(templates: ComponentTemplate[])"),"."),(0,_react2.mdx)("p",null,"To make the templates of an aspect available on a workspace, they need to be added to the workspace.jsonc. For example:"),(0,_react2.mdx)("pre",null,(0,_react2.mdx)("code",{parentName:"pre",className:"language-json"},`"teambit.generator/generator": {
|
3
|
+
"aspects": [
|
4
|
+
"teambit.harmony/aspect"
|
5
|
+
]
|
6
|
+
},
|
7
|
+
`)),(0,_react2.mdx)("p",null,"In the example above, the aspect ",(0,_react2.mdx)("inlineCode",{parentName:"p"},"teambit.harmony/aspect")," is configured to be available for the generator."),(0,_react2.mdx)("h2",null,"Show all available templates"),(0,_react2.mdx)("p",null,"Introduce a new command ",(0,_react2.mdx)("inlineCode",{parentName:"p"},"bit templates"),", which groups all available templates by aspects."),(0,_react2.mdx)("h2",null,"Hide core templates"),(0,_react2.mdx)("p",null,"Configure the Generator aspect to hide core templates when running ",(0,_react2.mdx)("inlineCode",{parentName:"p"},"bit templates"),". They'll be only shown when using ",(0,_react2.mdx)("inlineCode",{parentName:"p"},"--show-all")," flag."),(0,_react2.mdx)("pre",null,(0,_react2.mdx)("code",{parentName:"pre",className:"language-json"},`"teambit.generator/generator": {
|
8
|
+
"hideCoreTemplates": true
|
9
|
+
},
|
10
|
+
`)),(0,_react2.mdx)("h2",null,"Generate a template from CLI"),(0,_react2.mdx)("p",null,"Introduce a ",(0,_react2.mdx)("inlineCode",{parentName:"p"},"create")," command to use templates."),(0,_react2.mdx)("pre",null,(0,_react2.mdx)("code",{parentName:"pre",className:"language-sh"},`bit create <template-name> <component-name...> [--scope | -s] [--namespace | -n] [--aspect | -a]
|
11
|
+
`)),(0,_react2.mdx)("h3",null,"Args"),(0,_react2.mdx)("h4",null,(0,_react2.mdx)("inlineCode",{parentName:"h4"},"<component name>")),(0,_react2.mdx)("p",null,"Name of the component to create. Will be used as the component's dir name and fed to the component template."),(0,_react2.mdx)("p",null,(0,_react2.mdx)("strong",{parentName:"p"},"generated file structure should use kebab-case, while the template itself be in camel case"),"."),(0,_react2.mdx)("h3",null,"Options"),(0,_react2.mdx)("h4",null,(0,_react2.mdx)("inlineCode",{parentName:"h4"},"[--scope | -s]")),(0,_react2.mdx)("p",null,"Sets the component's scope and base directory. If not defined, use the ",(0,_react2.mdx)("inlineCode",{parentName:"p"},"defaultScope")," from ",(0,_react2.mdx)("inlineCode",{parentName:"p"},"teambit.workspace/workspace")," config."),(0,_react2.mdx)("h4",null,(0,_react2.mdx)("inlineCode",{parentName:"h4"},"[--namespace | -n]")),(0,_react2.mdx)("p",null,"Sets the component's namespace and nested dirs inside the scope. If not define, use empty string."),(0,_react2.mdx)("h4",null,(0,_react2.mdx)("inlineCode",{parentName:"h4"},"[--aspect | -a]")),(0,_react2.mdx)("p",null,"Aspect ID that registered this template, required only if there are two templates with the same name from several aspects in the workspace."),(0,_react2.mdx)("h2",null,"Creating a custom template generator"),(0,_react2.mdx)("p",null,"See our ",(0,_react2.mdx)("a",{parentName:"p",href:"https://harmony-docs.bit.dev/extending-bit/creating-a-custom-generator"},"tutorial")," on how to Create your own custom component generator."))}MDXContent.__bit_component=__bit_component,MDXContent.isMDXComponent=!0},736:function(__unused_webpack_module,exports2,__webpack_require__2){var __bit_component={id:"teambit.generator/aspect-docs/generator@0.0.165",homepage:"https://bit.cloud/teambit/generator/aspect-docs/generator",exported:!0},__importDefault=this&&this.__importDefault||function(mod){return mod&&mod.__esModule?mod:{default:mod}};Object.defineProperty(exports2,"__esModule",{value:!0}),exports2.Generator=void 0;var generator_mdx_1=__webpack_require__2(493);Object.defineProperty(exports2,"Generator",{enumerable:!0,get:function(){return __importDefault(generator_mdx_1).default}})},951:(__unused_webpack_module,exports2,__webpack_require__2)=>{var __bit_component={id:"teambit.generator/generator@6489e18b89a4a26b88b415fb314ab2af864f1df7",homepage:"https://bit.cloud/teambit/generator/generator",exported:!0};Object.defineProperty(exports2,"__esModule",{value:!0}),exports2.Logo=void 0;function _react(){const data=_interopRequireDefault(__webpack_require__2(363));return _react=function(){return data},data}_react.__bit_component=__bit_component;function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}_interopRequireDefault.__bit_component=__bit_component;const Logo=()=>_react().default.createElement("div",{style:{height:"100%",display:"flex",justifyContent:"center"}},_react().default.createElement("img",{style:{width:70},src:"https://static.bit.dev/extensions-icons/generator-new.svg"}));Logo.__bit_component=__bit_component,exports2.Logo=Logo},40:module2=>{module2.exports=MdxJsReact},363:module2=>{module2.exports=React}},__webpack_module_cache__={};function __webpack_require__(moduleId){var cachedModule=__webpack_module_cache__[moduleId];if(cachedModule!==void 0)return cachedModule.exports;var module2=__webpack_module_cache__[moduleId]={exports:{}};return __webpack_modules__[moduleId].call(module2.exports,module2,module2.exports,__webpack_require__),module2.exports}__webpack_require__.d=(exports2,definition)=>{for(var key in definition)__webpack_require__.o(definition,key)&&!__webpack_require__.o(exports2,key)&&Object.defineProperty(exports2,key,{enumerable:!0,get:definition[key]})},__webpack_require__.o=(obj,prop)=>Object.prototype.hasOwnProperty.call(obj,prop),__webpack_require__.r=exports2=>{typeof Symbol<"u"&&Symbol.toStringTag&&Object.defineProperty(exports2,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(exports2,"__esModule",{value:!0})};var __webpack_exports__={};return(()=>{__webpack_require__.r(__webpack_exports__),__webpack_require__.d(__webpack_exports__,{compositions:()=>compositions,compositions_metadata:()=>compositions_metadata,overview:()=>overview});var generator_docs_namespaceObject={};__webpack_require__.r(generator_docs_namespaceObject),__webpack_require__.d(generator_docs_namespaceObject,{default:()=>MDXContent});var generator_composition=__webpack_require__(951),external_React_=__webpack_require__(363),external_MdxJsReact_=__webpack_require__(40);const external_TeambitMdxUiMdxScopeContext_namespaceObject=TeambitMdxUiMdxScopeContext;var dist=__webpack_require__(736),_excluded=["components"];function _extends(){return _extends=Object.assign?Object.assign.bind():function(target){for(var i=1;i<arguments.length;i++){var source=arguments[i];for(var key in source)Object.prototype.hasOwnProperty.call(source,key)&&(target[key]=source[key])}return target},_extends.apply(this,arguments)}function _objectWithoutProperties(source,excluded){if(source==null)return{};var target=_objectWithoutPropertiesLoose(source,excluded),key,i;if(Object.getOwnPropertySymbols){var sourceSymbolKeys=Object.getOwnPropertySymbols(source);for(i=0;i<sourceSymbolKeys.length;i++)key=sourceSymbolKeys[i],!(excluded.indexOf(key)>=0)&&(!Object.prototype.propertyIsEnumerable.call(source,key)||(target[key]=source[key]))}return target}function _objectWithoutPropertiesLoose(source,excluded){if(source==null)return{};var target={},sourceKeys=Object.keys(source),key,i;for(i=0;i<sourceKeys.length;i++)key=sourceKeys[i],!(excluded.indexOf(key)>=0)&&(target[key]=source[key]);return target}var layoutProps={},MDXLayout="wrapper";function MDXContent(_ref){var components=_ref.components,props=_objectWithoutProperties(_ref,_excluded);return(0,external_MdxJsReact_.mdx)(MDXLayout,_extends({},layoutProps,props,{components,mdxType:"MDXLayout"}),(0,external_MdxJsReact_.mdx)(external_TeambitMdxUiMdxScopeContext_namespaceObject.MDXScopeProvider,{components:{Generator:dist.Generator},mdxType:"MDXScopeProvider"},(0,external_MdxJsReact_.mdx)(dist.Generator,{mdxType:"Generator"})))}MDXContent.isMDXComponent=!0;var __bit_component={id:"teambit.generator/generator@6489e18b89a4a26b88b415fb314ab2af864f1df7",homepage:"https://bit.cloud/teambit/generator/generator",exported:!0};const compositions=[generator_composition],overview=[generator_docs_namespaceObject],compositions_metadata={compositions:[{displayName:"Logo",identifier:"Logo"}]}})(),__webpack_exports__})());
|
package/template-list.ts
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
import { EnvContext, EnvHandler } from '@teambit/envs';
|
2
|
+
import { ComponentTemplate } from './component-template';
|
3
|
+
|
4
|
+
export type TemplateListOptions = {
|
5
|
+
name?: string;
|
6
|
+
};
|
7
|
+
|
8
|
+
export class TemplateList {
|
9
|
+
constructor(readonly name: string, private templates: EnvHandler<ComponentTemplate>[], private context: EnvContext) {}
|
10
|
+
|
11
|
+
compute(): ComponentTemplate[] {
|
12
|
+
return this.templates.map((template) => template(this.context));
|
13
|
+
}
|
14
|
+
|
15
|
+
static from(templates: EnvHandler<ComponentTemplate>[], options: TemplateListOptions = {}) {
|
16
|
+
return (context: EnvContext) => {
|
17
|
+
const name = options.name || 'template-list';
|
18
|
+
return new TemplateList(name, templates, context);
|
19
|
+
};
|
20
|
+
}
|
21
|
+
}
|
@@ -6,17 +6,22 @@ export const BasicWorkspaceStarter: Starter = {
|
|
6
6
|
name: 'basic',
|
7
7
|
description: 'a basic workspace',
|
8
8
|
generateFiles: async (context: WorkspaceContext) => {
|
9
|
-
|
9
|
+
const files = [
|
10
10
|
{
|
11
11
|
relativePath: 'workspace.jsonc',
|
12
12
|
content: await workspaceConfig(context),
|
13
13
|
},
|
14
|
-
|
14
|
+
];
|
15
|
+
|
16
|
+
if (!context.skipGit) {
|
17
|
+
files.push({
|
15
18
|
relativePath: '.gitignore',
|
16
19
|
content: gitIgnore(),
|
17
|
-
}
|
18
|
-
|
20
|
+
});
|
21
|
+
}
|
22
|
+
|
23
|
+
return files;
|
19
24
|
},
|
20
25
|
};
|
21
26
|
|
22
|
-
export default BasicWorkspaceStarter;
|
27
|
+
export default BasicWorkspaceStarter;
|
@@ -3,11 +3,11 @@ import { WorkspaceContext } from '../../../..';
|
|
3
3
|
|
4
4
|
export async function workspaceConfig({ name, defaultScope }: WorkspaceContext) {
|
5
5
|
const configParsed = await getWorkspaceConfigTemplateParsed();
|
6
|
-
const
|
6
|
+
const dependencyResolverDefaultConfig = configParsed['teambit.dependencies/dependency-resolver'];
|
7
7
|
configParsed['teambit.workspace/workspace'].name = name;
|
8
8
|
configParsed['teambit.workspace/workspace'].defaultScope = defaultScope || 'org.scope';
|
9
9
|
configParsed['teambit.dependencies/dependency-resolver'] = {
|
10
|
-
...
|
10
|
+
...dependencyResolverDefaultConfig,
|
11
11
|
policy: {
|
12
12
|
dependencies: {
|
13
13
|
'@teambit/node.node': 'latest',
|
@@ -25,6 +25,10 @@ export function starterFile({ namePascalCase, name }: ComponentContext) {
|
|
25
25
|
},
|
26
26
|
];
|
27
27
|
}
|
28
|
+
|
29
|
+
// import: () => [
|
30
|
+
// { id: 'teambit.community/component-showcase' },
|
31
|
+
// ]
|
28
32
|
|
29
33
|
static from(options: Partial<${namePascalCase}StarterOptions>) {
|
30
34
|
return () =>
|
@@ -37,4 +41,4 @@ export function starterFile({ namePascalCase, name }: ComponentContext) {
|
|
37
41
|
}
|
38
42
|
|
39
43
|
`;
|
40
|
-
}
|
44
|
+
}
|
@@ -3,20 +3,30 @@ export function workspaceConfigTemplate() {
|
|
3
3
|
import { getWorkspaceConfigTemplateParsed, stringifyWorkspaceConfig } from '@teambit/config';
|
4
4
|
|
5
5
|
export async function workspaceConfig({ name, defaultScope }: WorkspaceContext) {
|
6
|
-
const scope = defaultScope || 'org.scope';
|
7
6
|
const configParsed = await getWorkspaceConfigTemplateParsed();
|
7
|
+
const packageManagerDefaultConfig = configParsed['teambit.dependencies/dependency-resolver'];
|
8
8
|
configParsed['teambit.workspace/workspace'].name = name;
|
9
|
-
configParsed['teambit.workspace/workspace'].defaultScope = scope;
|
10
|
-
configParsed['teambit.
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
9
|
+
configParsed['teambit.workspace/workspace'].defaultScope = defaultScope || 'org.scope';
|
10
|
+
configParsed['teambit.dependencies/dependency-resolver'] = {
|
11
|
+
...packageManagerDefaultConfig,
|
12
|
+
policy: {
|
13
|
+
dependencies: {
|
14
|
+
'@teambit/node.node': 'latest',
|
15
|
+
'@types/node': '16.18.44',
|
16
|
+
'@types/jest': '29.5.4',
|
17
|
+
eslint: '7.32.0',
|
18
|
+
'@typescript-eslint/eslint-plugin': '5.62.0',
|
19
|
+
'eslint-import-resolver-node': '0.3.6',
|
20
|
+
'eslint-plugin-import': '2.22.1',
|
21
|
+
'eslint-plugin-jest': '24.1.5',
|
22
|
+
'eslint-plugin-jsx-a11y': '6.4.1',
|
23
|
+
'eslint-plugin-mdx': '1.17.1',
|
24
|
+
'eslint-plugin-react': '7.22.0',
|
25
|
+
},
|
26
|
+
},
|
17
27
|
};
|
18
28
|
|
19
29
|
return stringifyWorkspaceConfig(configParsed);
|
20
30
|
}
|
21
31
|
`;
|
22
|
-
}
|
32
|
+
}
|
@@ -28,8 +28,17 @@ export function starterFile({ namePascalCase, name }: ComponentContext) {
|
|
28
28
|
import: () => [
|
29
29
|
{ id: 'teambit.community/component-showcase' },
|
30
30
|
]
|
31
|
+
// you can also fork components
|
32
|
+
// fork: () => [
|
33
|
+
// {
|
34
|
+
// id: 'teambit.react/react-env-extension',
|
35
|
+
// targetName: 'envs/my-react-env',
|
36
|
+
// },
|
37
|
+
// ]
|
38
|
+
|
39
|
+
|
31
40
|
};
|
32
41
|
|
33
42
|
export default ${namePascalCase}WorkspaceStarter;
|
34
43
|
`;
|
35
|
-
}
|
44
|
+
}
|
@@ -4,19 +4,30 @@ import { getWorkspaceConfigTemplateParsed, stringifyWorkspaceConfig } from '@tea
|
|
4
4
|
|
5
5
|
export async function workspaceConfig({ name, defaultScope }: WorkspaceContext) {
|
6
6
|
const configParsed = await getWorkspaceConfigTemplateParsed();
|
7
|
+
const packageManagerDefaultConfig = configParsed['teambit.dependencies/dependency-resolver'];
|
7
8
|
configParsed['teambit.workspace/workspace'].name = name;
|
8
9
|
configParsed['teambit.workspace/workspace'].defaultScope = defaultScope || 'org.scope';
|
9
|
-
configParsed['teambit.
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
10
|
+
configParsed['teambit.dependencies/dependency-resolver'] = {
|
11
|
+
...packageManagerDefaultConfig,
|
12
|
+
policy: {
|
13
|
+
dependencies: {
|
14
|
+
'@teambit/node.node': 'latest',
|
15
|
+
'@types/node': '16.18.44',
|
16
|
+
'@types/jest': '29.5.4',
|
17
|
+
eslint: '7.32.0',
|
18
|
+
'@typescript-eslint/eslint-plugin': '5.62.0',
|
19
|
+
'eslint-import-resolver-node': '0.3.6',
|
20
|
+
'eslint-plugin-import': '2.22.1',
|
21
|
+
'eslint-plugin-jest': '24.1.5',
|
22
|
+
'eslint-plugin-jsx-a11y': '6.4.1',
|
23
|
+
'eslint-plugin-mdx': '1.17.1',
|
24
|
+
'eslint-plugin-react': '7.22.0',
|
25
|
+
},
|
26
|
+
},
|
17
27
|
};
|
18
28
|
|
29
|
+
|
19
30
|
return stringifyWorkspaceConfig(configParsed);
|
20
31
|
}
|
21
32
|
`;
|
22
|
-
}
|
33
|
+
}
|
package/templates.cmd.ts
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
import { Command, CommandOptions } from '@teambit/cli';
|
2
|
+
import chalk from 'chalk';
|
3
|
+
import { groupBy } from 'lodash';
|
4
|
+
import { GeneratorMain, TemplateDescriptor } from './generator.main.runtime';
|
5
|
+
|
6
|
+
export type TemplatesOptions = {
|
7
|
+
showAll?: boolean;
|
8
|
+
aspect?: string;
|
9
|
+
};
|
10
|
+
|
11
|
+
export class TemplatesCmd implements Command {
|
12
|
+
name = 'templates';
|
13
|
+
description = 'list available templates for "bit create" and "bit new"';
|
14
|
+
extendedDescription =
|
15
|
+
'list components templates when inside bit-workspace (for bit-create), otherwise, list workspace templates (for bit-new)';
|
16
|
+
alias = '';
|
17
|
+
loader = true;
|
18
|
+
group = 'development';
|
19
|
+
options = [
|
20
|
+
['s', 'show-all', 'show hidden templates'],
|
21
|
+
['a', 'aspect <aspect-id>', 'show templates provided by the aspect-id'],
|
22
|
+
] as CommandOptions;
|
23
|
+
|
24
|
+
constructor(private generator: GeneratorMain) {}
|
25
|
+
|
26
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
27
|
+
async report(args: [], templatesOptions: TemplatesOptions) {
|
28
|
+
let results = await this.generator.listTemplates(templatesOptions);
|
29
|
+
|
30
|
+
// Make sure that we don't list hidden templates
|
31
|
+
if (!templatesOptions.showAll) {
|
32
|
+
results = results.filter((template) => !template.hidden);
|
33
|
+
}
|
34
|
+
|
35
|
+
const grouped = groupBy(results, 'aspectId');
|
36
|
+
const titleStr = this.generator.isRunningInsideWorkspace()
|
37
|
+
? `The following template(s) are available with the command bit create: \nExample - bit create <template-name> <component-name>`
|
38
|
+
: `The following template(s) are available with the command bit new: \nExample - bit new <template-name> <workspace-name>`;
|
39
|
+
const title = chalk.green(`\n${titleStr}\n`);
|
40
|
+
const templateOutput = (template: TemplateDescriptor) => {
|
41
|
+
const desc = template.description ? ` (${template.description})` : '';
|
42
|
+
return ` ${template.name}${chalk.dim(desc)}`;
|
43
|
+
};
|
44
|
+
const output = Object.keys(grouped)
|
45
|
+
.map((aspectId) => {
|
46
|
+
const names = grouped[aspectId].map(templateOutput).join('\n');
|
47
|
+
const groupTitle = grouped[aspectId][0].titlePrefix
|
48
|
+
? `${grouped[aspectId][0].titlePrefix} (${aspectId})`
|
49
|
+
: aspectId;
|
50
|
+
return `${chalk.blue.bold(groupTitle)}\n${names}\n`;
|
51
|
+
})
|
52
|
+
.join('\n');
|
53
|
+
return title + output;
|
54
|
+
}
|
55
|
+
}
|
package/types.ts
ADDED
@@ -0,0 +1,205 @@
|
|
1
|
+
import fs from 'fs-extra';
|
2
|
+
import { loadBit } from '@teambit/bit';
|
3
|
+
import { Harmony } from '@teambit/harmony';
|
4
|
+
import { Component } from '@teambit/component';
|
5
|
+
import execa from 'execa';
|
6
|
+
import pMapSeries from 'p-map-series';
|
7
|
+
import UIAspect, { UiMain } from '@teambit/ui';
|
8
|
+
import { Logger, LoggerAspect, LoggerMain } from '@teambit/logger';
|
9
|
+
import { WorkspaceAspect, Workspace } from '@teambit/workspace';
|
10
|
+
import ForkingAspect, { ForkingMain } from '@teambit/forking';
|
11
|
+
import { init } from '@teambit/legacy/dist/api/consumer';
|
12
|
+
import ImporterAspect, { ImporterMain } from '@teambit/importer';
|
13
|
+
import { CompilerAspect, CompilerMain } from '@teambit/compiler';
|
14
|
+
import getGitExecutablePath from '@teambit/legacy/dist/utils/git/git-executable';
|
15
|
+
import GitNotFound from '@teambit/legacy/dist/utils/git/exceptions/git-not-found';
|
16
|
+
import { resolve, join } from 'path';
|
17
|
+
import { ComponentID } from '@teambit/component-id';
|
18
|
+
import GitAspect, { GitMain } from '@teambit/git';
|
19
|
+
import { InstallAspect, InstallMain } from '@teambit/install';
|
20
|
+
import WorkspaceConfigFilesAspect, { WorkspaceConfigFilesMain } from '@teambit/workspace-config-files';
|
21
|
+
// import { ComponentGenerator } from './component-generator';
|
22
|
+
import { WorkspaceTemplate, WorkspaceContext } from './workspace-template';
|
23
|
+
import { NewOptions } from './new.cmd';
|
24
|
+
import { GeneratorAspect } from './generator.aspect';
|
25
|
+
|
26
|
+
export type GenerateResult = { id: ComponentID; dir: string; files: string[]; envId: string };
|
27
|
+
|
28
|
+
export class WorkspaceGenerator {
|
29
|
+
private workspacePath: string;
|
30
|
+
private harmony: Harmony;
|
31
|
+
private workspace: Workspace;
|
32
|
+
private install: InstallMain;
|
33
|
+
private importer: ImporterMain;
|
34
|
+
private logger?: Logger;
|
35
|
+
private forking: ForkingMain;
|
36
|
+
private git: GitMain;
|
37
|
+
private wsConfigFiles: WorkspaceConfigFilesMain;
|
38
|
+
// private componentGenerator?: ComponentGenerator;
|
39
|
+
|
40
|
+
constructor(
|
41
|
+
private workspaceName: string,
|
42
|
+
private options: NewOptions,
|
43
|
+
private template: WorkspaceTemplate,
|
44
|
+
private aspectComponent?: Component
|
45
|
+
) {
|
46
|
+
this.workspacePath = resolve(this.workspaceName);
|
47
|
+
}
|
48
|
+
|
49
|
+
async generate(): Promise<string> {
|
50
|
+
if (fs.existsSync(this.workspacePath)) {
|
51
|
+
throw new Error(`unable to create a workspace at "${this.workspaceName}", this path already exist`);
|
52
|
+
}
|
53
|
+
await fs.ensureDir(this.workspacePath);
|
54
|
+
try {
|
55
|
+
process.chdir(this.workspacePath);
|
56
|
+
await this.initGit();
|
57
|
+
await init(this.workspacePath, this.options.skipGit, false, false, false, false, false, false, {});
|
58
|
+
await this.writeWorkspaceFiles();
|
59
|
+
await this.reloadBitInWorkspaceDir();
|
60
|
+
// Setting the workspace to be in install context to prevent errors during the workspace generation
|
61
|
+
// the workspace will be in install context until the end of the generation install process
|
62
|
+
this.workspace.inInstallContext = true;
|
63
|
+
await this.setupGitBitmapMergeDriver();
|
64
|
+
await this.forkComponentsFromRemote();
|
65
|
+
await this.importComponentsFromRemote();
|
66
|
+
await this.workspace.clearCache();
|
67
|
+
await this.install.install(undefined, {
|
68
|
+
dedupe: true,
|
69
|
+
import: false,
|
70
|
+
copyPeerToRuntimeOnRoot: true,
|
71
|
+
copyPeerToRuntimeOnComponents: false,
|
72
|
+
updateExisting: false,
|
73
|
+
});
|
74
|
+
|
75
|
+
// compile the components again now that we have the dependencies installed
|
76
|
+
await this.compileComponents(true);
|
77
|
+
await this.wsConfigFiles.writeConfigFiles({});
|
78
|
+
} catch (err: any) {
|
79
|
+
this.logger?.error(`failed generating a new workspace, will delete the dir ${this.workspacePath}`, err);
|
80
|
+
await fs.remove(this.workspacePath);
|
81
|
+
throw err;
|
82
|
+
}
|
83
|
+
|
84
|
+
return this.workspacePath;
|
85
|
+
}
|
86
|
+
|
87
|
+
private async initGit() {
|
88
|
+
if (this.options.skipGit) return;
|
89
|
+
const gitExecutablePath = getGitExecutablePath();
|
90
|
+
const params = ['init'];
|
91
|
+
try {
|
92
|
+
await execa(gitExecutablePath, params);
|
93
|
+
} catch (err: any) {
|
94
|
+
if (err.exitCodeName === 'ENOENT') {
|
95
|
+
throw new GitNotFound(gitExecutablePath, err);
|
96
|
+
}
|
97
|
+
throw err;
|
98
|
+
}
|
99
|
+
}
|
100
|
+
|
101
|
+
private async setupGitBitmapMergeDriver() {
|
102
|
+
if (this.options.skipGit) return;
|
103
|
+
await this.git.setGitMergeDriver({ global: false });
|
104
|
+
}
|
105
|
+
|
106
|
+
private async buildUI() {
|
107
|
+
const uiMain = this.harmony.get<UiMain>(UIAspect.id);
|
108
|
+
await uiMain.createRuntime({});
|
109
|
+
}
|
110
|
+
|
111
|
+
private getWorkspaceContext(): WorkspaceContext {
|
112
|
+
return {
|
113
|
+
name: this.workspaceName,
|
114
|
+
defaultScope: this.options.defaultScope,
|
115
|
+
empty: this.options.empty,
|
116
|
+
aspectComponent: this.aspectComponent,
|
117
|
+
template: this.template,
|
118
|
+
skipGit: this.options.skipGit,
|
119
|
+
};
|
120
|
+
}
|
121
|
+
|
122
|
+
/**
|
123
|
+
* writes the generated template files to the default directory set in the workspace config
|
124
|
+
*/
|
125
|
+
private async writeWorkspaceFiles(): Promise<void> {
|
126
|
+
const workspaceContext = this.getWorkspaceContext();
|
127
|
+
const templateFiles = await this.template.generateFiles(workspaceContext);
|
128
|
+
await Promise.all(
|
129
|
+
templateFiles.map(async (templateFile) => {
|
130
|
+
await fs.outputFile(join(this.workspacePath, templateFile.relativePath), templateFile.content);
|
131
|
+
})
|
132
|
+
);
|
133
|
+
}
|
134
|
+
|
135
|
+
private async reloadBitInWorkspaceDir() {
|
136
|
+
this.harmony = await loadBit(this.workspacePath);
|
137
|
+
this.workspace = this.harmony.get<Workspace>(WorkspaceAspect.id);
|
138
|
+
this.install = this.harmony.get<InstallMain>(InstallAspect.id);
|
139
|
+
const loggerMain = this.harmony.get<LoggerMain>(LoggerAspect.id);
|
140
|
+
this.logger = loggerMain.createLogger(GeneratorAspect.id);
|
141
|
+
this.importer = this.harmony.get<ImporterMain>(ImporterAspect.id);
|
142
|
+
this.forking = this.harmony.get<ForkingMain>(ForkingAspect.id);
|
143
|
+
this.git = this.harmony.get<GitMain>(GitAspect.id);
|
144
|
+
this.wsConfigFiles = this.harmony.get<WorkspaceConfigFilesMain>(WorkspaceConfigFilesAspect.id);
|
145
|
+
}
|
146
|
+
|
147
|
+
// WIP
|
148
|
+
// private async createComponentsFromRemote() {
|
149
|
+
// if (this.options.empty || !this.template.create) return
|
150
|
+
// const workspaceContext = this.getWorkspaceContext();
|
151
|
+
// const componentsToCreate = this.template.create(workspaceContext)
|
152
|
+
// await pMapSeries(componentsToCreate, async (componentToCreate) => {
|
153
|
+
// await ComponentGenerator.generate(componentToCreate);
|
154
|
+
// });
|
155
|
+
// }
|
156
|
+
|
157
|
+
private async forkComponentsFromRemote() {
|
158
|
+
if (this.options.empty) return;
|
159
|
+
const workspaceContext = this.getWorkspaceContext();
|
160
|
+
const componentsToFork =
|
161
|
+
this.template?.importComponents?.(workspaceContext) || this.template?.fork?.(workspaceContext) || [];
|
162
|
+
if (!componentsToFork.length) return;
|
163
|
+
const componentsToForkRestructured = componentsToFork.map(({ id, targetName, path, env, config }) => ({
|
164
|
+
sourceId: id,
|
165
|
+
targetId: targetName,
|
166
|
+
path,
|
167
|
+
env,
|
168
|
+
config,
|
169
|
+
}));
|
170
|
+
await this.forking.forkMultipleFromRemote(componentsToForkRestructured, {
|
171
|
+
scope: this.workspace.defaultScope,
|
172
|
+
refactor: true,
|
173
|
+
install: false,
|
174
|
+
});
|
175
|
+
}
|
176
|
+
|
177
|
+
private async importComponentsFromRemote() {
|
178
|
+
if (this.options.empty) return;
|
179
|
+
const workspaceContext = this.getWorkspaceContext();
|
180
|
+
const componentsToImport = this.template?.import?.(workspaceContext) || [];
|
181
|
+
|
182
|
+
if (!componentsToImport.length) return;
|
183
|
+
|
184
|
+
await pMapSeries(componentsToImport, async (componentToImport) => {
|
185
|
+
await this.importer.import(
|
186
|
+
{
|
187
|
+
ids: [componentToImport.id],
|
188
|
+
installNpmPackages: false,
|
189
|
+
writeToPath: componentToImport.path,
|
190
|
+
},
|
191
|
+
[]
|
192
|
+
);
|
193
|
+
});
|
194
|
+
|
195
|
+
await this.workspace.bitMap.write();
|
196
|
+
}
|
197
|
+
|
198
|
+
private async compileComponents(clearCache = true) {
|
199
|
+
if (clearCache) {
|
200
|
+
await this.workspace.clearCache();
|
201
|
+
}
|
202
|
+
const compiler = this.harmony.get<CompilerMain>(CompilerAspect.id);
|
203
|
+
await compiler.compileOnWorkspace();
|
204
|
+
}
|
205
|
+
}
|