wlmaker 1.5.0 → 1.7.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.
@@ -0,0 +1,83 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/dart/injector.ts
4
+ import * as fs from "fs";
5
+ function injectMethod(filePath, className, methodCode, dedupKey) {
6
+ const content = fs.readFileSync(filePath, "utf8");
7
+ const dedup = dedupKey ?? findSignature(methodCode);
8
+ if (dedup && content.includes(dedup)) {
9
+ return;
10
+ }
11
+ const classRegex = new RegExp(`class\\s+${className}\\s*[^{]*\\{`);
12
+ const classMatch = content.match(classRegex);
13
+ if (!classMatch) {
14
+ throw new Error(`Class "${className}" not found in ${filePath}`);
15
+ }
16
+ const classStart = content.indexOf(classMatch[0]);
17
+ let braceCount = 0;
18
+ let classEnd = -1;
19
+ let foundOpen = false;
20
+ for (let i = classStart; i < content.length; i++) {
21
+ if (content[i] === "{") {
22
+ braceCount++;
23
+ foundOpen = true;
24
+ } else if (content[i] === "}") {
25
+ braceCount--;
26
+ if (foundOpen && braceCount === 0) {
27
+ classEnd = i;
28
+ break;
29
+ }
30
+ }
31
+ }
32
+ if (classEnd === -1) {
33
+ throw new Error(`Could not find closing brace for class "${className}" in ${filePath}`);
34
+ }
35
+ const indentedMethod = methodCode.split("\n").map((line) => line.trim() ? ` ${line}` : "").join("\n");
36
+ const newContent = content.slice(0, classEnd) + "\n" + indentedMethod + "\n" + content.slice(classEnd);
37
+ fs.writeFileSync(filePath, newContent);
38
+ }
39
+ function injectImport(filePath, importLine) {
40
+ const content = fs.readFileSync(filePath, "utf8");
41
+ if (content.includes(importLine.trim())) {
42
+ return;
43
+ }
44
+ const importRegex = /^import\s+[^;]+;/gm;
45
+ const imports = [...content.matchAll(importRegex)];
46
+ if (imports.length > 0) {
47
+ const lastImport = imports[imports.length - 1];
48
+ const insertPos = lastImport.index + lastImport[0].length;
49
+ const newContent = content.slice(0, insertPos) + "\n" + importLine + content.slice(insertPos);
50
+ fs.writeFileSync(filePath, newContent);
51
+ } else {
52
+ fs.writeFileSync(filePath, importLine + "\n\n" + content);
53
+ }
54
+ }
55
+ function injectExport(filePath, exportLine) {
56
+ let content = "";
57
+ if (fs.existsSync(filePath)) {
58
+ content = fs.readFileSync(filePath, "utf8");
59
+ }
60
+ if (content.includes(exportLine)) {
61
+ return;
62
+ }
63
+ const lines = content.split("\n").filter((l) => l.trim().length > 0);
64
+ lines.push(exportLine);
65
+ lines.sort();
66
+ fs.writeFileSync(filePath, lines.join("\n") + "\n");
67
+ }
68
+ function findSignature(methodCode) {
69
+ const lines = methodCode.trim().split("\n");
70
+ for (const line of lines) {
71
+ const stripped = line.trim();
72
+ if (stripped && !stripped.startsWith("@")) {
73
+ return stripped;
74
+ }
75
+ }
76
+ return null;
77
+ }
78
+
79
+ export {
80
+ injectMethod,
81
+ injectImport,
82
+ injectExport
83
+ };
@@ -0,0 +1,79 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ injectExport
4
+ } from "./chunk-7KUDXB2F.mjs";
5
+ import {
6
+ collaborativePageTemplate,
7
+ collaborativeViewTemplate
8
+ } from "./chunk-OTFDN3HG.mjs";
9
+
10
+ // src/generators/collaborative/page/generator.ts
11
+ import * as fs from "fs";
12
+ import * as path from "path";
13
+ import chalk from "chalk";
14
+ import { pascalCase } from "change-case";
15
+ var SNAKE_CASE_REGEX = /^[a-z][a-z0-9_]*$/;
16
+ async function createCollaborativePage(options) {
17
+ const { featurePath, pageName } = options;
18
+ const pascal = pascalCase(pageName);
19
+ if (!SNAKE_CASE_REGEX.test(pageName)) {
20
+ throw new Error(
21
+ "Page name must be snake_case (lowercase letters, digits, underscores)."
22
+ );
23
+ }
24
+ const lib = path.join(featurePath, "lib");
25
+ const pagesDir = path.join(lib, "presentation", "pages");
26
+ const viewsDir = path.join(pagesDir, "views");
27
+ if (!fs.existsSync(pagesDir)) {
28
+ throw new Error(
29
+ `Not a collaborative feature structure. Missing: ${pagesDir}`
30
+ );
31
+ }
32
+ fs.mkdirSync(viewsDir, { recursive: true });
33
+ const pageFile = path.join(pagesDir, `${pageName}_page.dart`);
34
+ const viewFile = path.join(viewsDir, `${pageName}_view.dart`);
35
+ if (fs.existsSync(pageFile)) {
36
+ throw new Error(`Page "${pageName}" already exists at ${pageFile}`);
37
+ }
38
+ const featureName = extractFeatureName(featurePath);
39
+ fs.writeFileSync(
40
+ pageFile,
41
+ collaborativePageTemplate(pageName, pascal)
42
+ );
43
+ console.log(chalk.green(` Page created: ${pageFile}`));
44
+ fs.writeFileSync(viewFile, collaborativeViewTemplate(pascal));
45
+ console.log(chalk.green(` View created: ${viewFile}`));
46
+ if (featureName) {
47
+ const viewsBarrel = path.join(viewsDir, "views.dart");
48
+ injectExport(viewsBarrel, `export '${pageName}_view.dart';`);
49
+ const pagesBarrel = path.join(pagesDir, "pages.dart");
50
+ injectExport(pagesBarrel, `export '${pageName}_page.dart';`);
51
+ injectExport(pagesBarrel, `export 'views/views.dart';`);
52
+ const mainBarrel = path.join(lib, `${featureName}.dart`);
53
+ if (fs.existsSync(mainBarrel)) {
54
+ const content = fs.readFileSync(mainBarrel, "utf8");
55
+ if (!content.includes(`export 'presentation/pages/${pageName}_page.dart';`)) {
56
+ injectExport(
57
+ mainBarrel,
58
+ `export 'presentation/pages/${pageName}_page.dart';`
59
+ );
60
+ }
61
+ if (!content.includes(`export 'presentation/pages/views/${pageName}_view.dart';`)) {
62
+ injectExport(
63
+ mainBarrel,
64
+ `export 'presentation/pages/views/${pageName}_view.dart';`
65
+ );
66
+ }
67
+ }
68
+ }
69
+ }
70
+ function extractFeatureName(featurePath) {
71
+ const normalized = featurePath.replace(/\\/g, "/");
72
+ const match = normalized.match(/\/([^/]+)\/lib\/?$/);
73
+ if (match) return match[1];
74
+ return path.basename(featurePath);
75
+ }
76
+
77
+ export {
78
+ createCollaborativePage
79
+ };
@@ -0,0 +1,146 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ resolveWorkspaceVersions
4
+ } from "./chunk-KBIXWYFD.mjs";
5
+ import {
6
+ blocsModuleTemplate,
7
+ collaborativeGitignore,
8
+ collaborativePubspec,
9
+ datasourcesModuleTemplate,
10
+ emptyBarrelTemplate,
11
+ featureDiTemplate,
12
+ mainBarrelTemplate,
13
+ repositoriesModuleTemplate,
14
+ usecasesModuleTemplate
15
+ } from "./chunk-OTFDN3HG.mjs";
16
+
17
+ // src/generators/collaborative/feature/generator.ts
18
+ import * as fs from "fs";
19
+ import * as path from "path";
20
+ import { execSync } from "child_process";
21
+ import chalk from "chalk";
22
+ import { pascalCase } from "change-case";
23
+ var SNAKE_CASE_REGEX = /^[a-z][a-z0-9_]*$/;
24
+ async function createCollaborativeFeature(options) {
25
+ const { monorepoRoot, featureName } = options;
26
+ const pascal = pascalCase(featureName);
27
+ const description = options.description ?? `${pascal} collaborative feature`;
28
+ if (!SNAKE_CASE_REGEX.test(featureName)) {
29
+ throw new Error(
30
+ "Feature name must be snake_case (lowercase letters, digits, underscores)."
31
+ );
32
+ }
33
+ const collaborativeDir = path.join(monorepoRoot, "packages", "collaborative");
34
+ if (!fs.existsSync(collaborativeDir)) {
35
+ fs.mkdirSync(collaborativeDir, { recursive: true });
36
+ }
37
+ const pkgDir = path.join(collaborativeDir, featureName);
38
+ if (fs.existsSync(pkgDir)) {
39
+ throw new Error(`packages/collaborative/${featureName} already exists`);
40
+ }
41
+ console.log(
42
+ chalk.bold(`
43
+ Creating collaborative feature: ${chalk.cyan(featureName)}
44
+ `)
45
+ );
46
+ console.log(chalk.cyan(" -> Running flutter create..."));
47
+ execSync(
48
+ `flutter create --template=package packages/collaborative/${featureName}`,
49
+ { cwd: monorepoRoot, stdio: "pipe" }
50
+ );
51
+ const autoTestFile = path.join(pkgDir, "test", `${featureName}_test.dart`);
52
+ if (fs.existsSync(autoTestFile)) {
53
+ fs.unlinkSync(autoTestFile);
54
+ }
55
+ console.log(chalk.cyan(" -> Generating feature structure..."));
56
+ const lib = path.join(pkgDir, "lib");
57
+ const dirs = [
58
+ path.join(lib, "data", "api", "bff"),
59
+ path.join(lib, "data", "datasources"),
60
+ path.join(lib, "data", "models"),
61
+ path.join(lib, "data", "repositories"),
62
+ path.join(lib, "domain", "entities"),
63
+ path.join(lib, "domain", "repositories"),
64
+ path.join(lib, "domain", "usecases"),
65
+ path.join(lib, "presentation", "bloc"),
66
+ path.join(lib, "presentation", "pages", "views"),
67
+ path.join(lib, "di")
68
+ ];
69
+ for (const dir of dirs) {
70
+ fs.mkdirSync(dir, { recursive: true });
71
+ }
72
+ const workspaceVersions = resolveWorkspaceVersions(monorepoRoot);
73
+ fs.writeFileSync(
74
+ path.join(pkgDir, "pubspec.yaml"),
75
+ collaborativePubspec(featureName, description, workspaceVersions)
76
+ );
77
+ fs.writeFileSync(
78
+ path.join(pkgDir, ".gitignore"),
79
+ collaborativeGitignore()
80
+ );
81
+ const diDir = path.join(lib, "di");
82
+ fs.writeFileSync(
83
+ path.join(diDir, `${featureName}_di.dart`),
84
+ featureDiTemplate(featureName)
85
+ );
86
+ fs.writeFileSync(
87
+ path.join(diDir, "blocs_module.dart"),
88
+ blocsModuleTemplate(featureName)
89
+ );
90
+ fs.writeFileSync(
91
+ path.join(diDir, "datasources_module.dart"),
92
+ datasourcesModuleTemplate(featureName)
93
+ );
94
+ fs.writeFileSync(
95
+ path.join(diDir, "repositories_module.dart"),
96
+ repositoriesModuleTemplate(featureName)
97
+ );
98
+ fs.writeFileSync(
99
+ path.join(diDir, "usecases_module.dart"),
100
+ usecasesModuleTemplate(featureName)
101
+ );
102
+ const barrelPaths = [
103
+ path.join(lib, "data", "api", "bff", "bff.dart"),
104
+ path.join(lib, "data", "datasources", "datasources.dart"),
105
+ path.join(lib, "data", "models", "models.dart"),
106
+ path.join(lib, "data", "repositories", "repositories.dart"),
107
+ path.join(lib, "domain", "entities", "entities.dart"),
108
+ path.join(lib, "domain", "repositories", "repositories.dart"),
109
+ path.join(lib, "domain", "usecases", "usecases.dart"),
110
+ path.join(lib, "presentation", "bloc", "bloc.dart"),
111
+ path.join(lib, "presentation", "pages", "views", "views.dart"),
112
+ path.join(lib, "presentation", "pages", "pages.dart")
113
+ ];
114
+ for (const barrelPath of barrelPaths) {
115
+ fs.writeFileSync(barrelPath, emptyBarrelTemplate());
116
+ }
117
+ fs.writeFileSync(
118
+ path.join(lib, `${featureName}.dart`),
119
+ mainBarrelTemplate(featureName)
120
+ );
121
+ if (options.runBootstrap !== false) {
122
+ console.log(chalk.cyan(" -> Running melos bootstrap..."));
123
+ try {
124
+ execSync("melos bootstrap", { cwd: monorepoRoot, stdio: "pipe" });
125
+ console.log(chalk.green(" melos bootstrap completed"));
126
+ } catch {
127
+ console.log(
128
+ chalk.yellow(" melos bootstrap failed (you may need to run it manually)")
129
+ );
130
+ }
131
+ }
132
+ console.log(
133
+ chalk.green(`
134
+ Feature "${featureName}" created successfully!`)
135
+ );
136
+ console.log(chalk.gray(` ${pkgDir}`));
137
+ console.log(chalk.gray(`
138
+ Next steps:`));
139
+ console.log(chalk.gray(` wlmaker collaborative endpoint ...`));
140
+ console.log(chalk.gray(` wlmaker collaborative bloc ...`));
141
+ console.log(chalk.gray(` wlmaker collaborative page ...`));
142
+ }
143
+
144
+ export {
145
+ createCollaborativeFeature
146
+ };
@@ -0,0 +1,164 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/analyzer/project.ts
4
+ import * as fs from "fs";
5
+ import * as path from "path";
6
+ import YAML from "yaml";
7
+ function analyzeProject(startDir) {
8
+ const projectRoot = findPubspecDir(startDir);
9
+ if (!projectRoot) return null;
10
+ const pubspecPath = path.join(projectRoot, "pubspec.yaml");
11
+ const content = fs.readFileSync(pubspecPath, "utf8");
12
+ const pubspec = YAML.parse(content);
13
+ const deps = {
14
+ ...pubspec?.dependencies,
15
+ ...pubspec?.dev_dependencies
16
+ };
17
+ const features = discoverFeatures(projectRoot);
18
+ return {
19
+ projectRoot,
20
+ projectName: pubspec?.name ?? path.basename(projectRoot),
21
+ hasFreezed: "freezed" in deps || "freezed_annotation" in deps,
22
+ hasBloc: "flutter_bloc" in deps || "bloc" in deps,
23
+ hasBuildRunner: "build_runner" in deps,
24
+ features
25
+ };
26
+ }
27
+ function findPubspecDir(startDir) {
28
+ let dir = startDir;
29
+ while (dir !== path.dirname(dir)) {
30
+ if (fs.existsSync(path.join(dir, "pubspec.yaml"))) {
31
+ return dir;
32
+ }
33
+ dir = path.dirname(dir);
34
+ }
35
+ return void 0;
36
+ }
37
+ function discoverFeatures(projectRoot) {
38
+ const featuresDir = path.join(projectRoot, "lib", "features");
39
+ if (!fs.existsSync(featuresDir)) return [];
40
+ return fs.readdirSync(featuresDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name).sort();
41
+ }
42
+ function findMonorepoRoot(startDir) {
43
+ let dir = startDir;
44
+ while (dir !== path.dirname(dir)) {
45
+ if (fs.existsSync(path.join(dir, "melos.yaml"))) {
46
+ return dir;
47
+ }
48
+ dir = path.dirname(dir);
49
+ }
50
+ return void 0;
51
+ }
52
+ function discoverPackages(monorepoRoot) {
53
+ const packageDirs = ["packages", "packages/features"];
54
+ const projects = [];
55
+ for (const base of packageDirs) {
56
+ const baseDir = path.join(monorepoRoot, base);
57
+ if (!fs.existsSync(baseDir)) continue;
58
+ const entries = fs.readdirSync(baseDir, { withFileTypes: true });
59
+ for (const entry of entries) {
60
+ if (!entry.isDirectory()) continue;
61
+ const candidate = path.join(baseDir, entry.name);
62
+ if (!fs.existsSync(path.join(candidate, "pubspec.yaml"))) continue;
63
+ const project = analyzeProject(candidate);
64
+ if (project && (project.hasFreezed || project.hasBloc)) {
65
+ projects.push(project);
66
+ }
67
+ }
68
+ }
69
+ return projects.sort((a, b) => a.projectName.localeCompare(b.projectName));
70
+ }
71
+ function discoverCollaborativeFeatures(monorepoRoot) {
72
+ const collabDir = path.join(monorepoRoot, "packages", "collaborative");
73
+ if (!fs.existsSync(collabDir)) return [];
74
+ const projects = [];
75
+ const entries = fs.readdirSync(collabDir, { withFileTypes: true });
76
+ for (const entry of entries) {
77
+ if (!entry.isDirectory()) continue;
78
+ const candidate = path.join(collabDir, entry.name);
79
+ if (!fs.existsSync(path.join(candidate, "pubspec.yaml"))) continue;
80
+ const project = analyzeProject(candidate);
81
+ if (project) {
82
+ projects.push(project);
83
+ }
84
+ }
85
+ return projects.sort((a, b) => a.projectName.localeCompare(b.projectName));
86
+ }
87
+ var REFERENCE_PACKAGES = ["packages/core", "packages/app_base", "packages/design_system"];
88
+ function resolveWorkspaceVersions(monorepoRoot) {
89
+ const merged = {
90
+ dependencies: {},
91
+ devDependencies: {},
92
+ dependencyOverrides: {}
93
+ };
94
+ for (const relPath of REFERENCE_PACKAGES) {
95
+ const pubspecPath = path.join(monorepoRoot, relPath, "pubspec.yaml");
96
+ if (!fs.existsSync(pubspecPath)) continue;
97
+ const content = fs.readFileSync(pubspecPath, "utf8");
98
+ const pubspec = YAML.parse(content);
99
+ if (pubspec?.dependencies) {
100
+ for (const [name, version] of Object.entries(pubspec.dependencies)) {
101
+ if (typeof version === "string") {
102
+ merged.dependencies[name] = version;
103
+ }
104
+ }
105
+ }
106
+ if (pubspec?.dev_dependencies) {
107
+ for (const [name, version] of Object.entries(pubspec.dev_dependencies)) {
108
+ if (typeof version === "string") {
109
+ merged.devDependencies[name] = version;
110
+ }
111
+ }
112
+ }
113
+ if (pubspec?.dependency_overrides) {
114
+ for (const [name, version] of Object.entries(pubspec.dependency_overrides)) {
115
+ if (typeof version === "string") {
116
+ merged.dependencyOverrides[name] = version;
117
+ }
118
+ }
119
+ }
120
+ }
121
+ return merged;
122
+ }
123
+ var IGNORED_DIRS = /* @__PURE__ */ new Set([
124
+ "node_modules",
125
+ ".dart_tool",
126
+ "build",
127
+ ".git",
128
+ ".idea",
129
+ ".fvm",
130
+ "coverage"
131
+ ]);
132
+ function discoverProjects(searchDir, maxDepth = 2) {
133
+ const projects = [];
134
+ function walk(dir, depth) {
135
+ if (depth > maxDepth) return;
136
+ const project = analyzeProject(dir);
137
+ if (project && (project.hasFreezed || project.hasBloc)) {
138
+ projects.push(project);
139
+ return;
140
+ }
141
+ if (!fs.existsSync(dir)) return;
142
+ let entries;
143
+ try {
144
+ entries = fs.readdirSync(dir, { withFileTypes: true });
145
+ } catch {
146
+ return;
147
+ }
148
+ for (const entry of entries) {
149
+ if (!entry.isDirectory() || IGNORED_DIRS.has(entry.name)) continue;
150
+ walk(path.join(dir, entry.name), depth + 1);
151
+ }
152
+ }
153
+ walk(searchDir, 0);
154
+ return projects.sort((a, b) => a.projectName.localeCompare(b.projectName));
155
+ }
156
+
157
+ export {
158
+ analyzeProject,
159
+ findMonorepoRoot,
160
+ discoverPackages,
161
+ discoverCollaborativeFeatures,
162
+ resolveWorkspaceVersions,
163
+ discoverProjects
164
+ };
@@ -0,0 +1,85 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ injectMethod
4
+ } from "./chunk-7KUDXB2F.mjs";
5
+ import {
6
+ blocRegistrationSnippet,
7
+ collaborativeBlocEventTemplate,
8
+ collaborativeBlocStateTemplate,
9
+ collaborativeBlocTemplate
10
+ } from "./chunk-OTFDN3HG.mjs";
11
+
12
+ // src/generators/collaborative/bloc/generator.ts
13
+ import * as fs from "fs";
14
+ import * as path from "path";
15
+ import chalk from "chalk";
16
+ import { pascalCase } from "change-case";
17
+ var SNAKE_CASE_REGEX = /^[a-z][a-z0-9_]*$/;
18
+ async function createCollaborativeBloc(options) {
19
+ const { featurePath, blocName } = options;
20
+ const pascal = pascalCase(blocName);
21
+ if (!SNAKE_CASE_REGEX.test(blocName)) {
22
+ throw new Error(
23
+ "BLoC name must be snake_case (lowercase letters, digits, underscores)."
24
+ );
25
+ }
26
+ const lib = path.join(featurePath, "lib");
27
+ const blocDir = path.join(lib, "presentation", "bloc");
28
+ if (!fs.existsSync(blocDir)) {
29
+ throw new Error(
30
+ `Not a collaborative feature structure. Missing: ${blocDir}`
31
+ );
32
+ }
33
+ const blocFile = path.join(blocDir, `${blocName}_bloc.dart`);
34
+ if (fs.existsSync(blocFile)) {
35
+ throw new Error(`BLoC "${blocName}" already exists at ${blocFile}`);
36
+ }
37
+ fs.writeFileSync(
38
+ blocFile,
39
+ collaborativeBlocTemplate(blocName, pascal)
40
+ );
41
+ console.log(chalk.green(` BLoC created: ${blocFile}`));
42
+ fs.writeFileSync(
43
+ path.join(blocDir, `${blocName}_event.dart`),
44
+ collaborativeBlocEventTemplate(blocName, pascal)
45
+ );
46
+ fs.writeFileSync(
47
+ path.join(blocDir, `${blocName}_state.dart`),
48
+ collaborativeBlocStateTemplate(blocName, pascal)
49
+ );
50
+ console.log(chalk.green(` Event + State files created`));
51
+ const barrelPath = path.join(blocDir, "bloc.dart");
52
+ const exportLine = `export '${blocName}_bloc.dart';`;
53
+ if (fs.existsSync(barrelPath)) {
54
+ const content = fs.readFileSync(barrelPath, "utf8");
55
+ if (!content.includes(exportLine)) {
56
+ fs.writeFileSync(barrelPath, content.trimEnd() + "\n" + exportLine + "\n");
57
+ }
58
+ } else {
59
+ fs.writeFileSync(barrelPath, exportLine + "\n");
60
+ }
61
+ const featureName = path.basename(featurePath);
62
+ const diDir = path.join(lib, "di");
63
+ const blocsModulePath = path.join(diDir, "blocs_module.dart");
64
+ if (fs.existsSync(blocsModulePath)) {
65
+ const snippet = blocRegistrationSnippet(blocName, pascal);
66
+ const importLine = `import 'package:${featureName}/presentation/bloc/${blocName}_bloc.dart';`;
67
+ const content = fs.readFileSync(blocsModulePath, "utf8");
68
+ if (!content.includes(importLine)) {
69
+ const importRegex = /^import\s+[^;]+;/gm;
70
+ const imports = [...content.matchAll(importRegex)];
71
+ if (imports.length > 0) {
72
+ const lastImport = imports[imports.length - 1];
73
+ const insertPos = lastImport.index + lastImport[0].length;
74
+ const newContent = content.slice(0, insertPos) + "\n" + importLine + content.slice(insertPos);
75
+ fs.writeFileSync(blocsModulePath, newContent);
76
+ }
77
+ }
78
+ injectMethod(blocsModulePath, "BlocsModule", snippet);
79
+ console.log(chalk.green(" Registered in BlocsModule"));
80
+ }
81
+ }
82
+
83
+ export {
84
+ createCollaborativeBloc
85
+ };