juo 0.1.0 → 0.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.
package/README.md CHANGED
@@ -20,7 +20,7 @@ $ npm install -g juo
20
20
  $ juo COMMAND
21
21
  running command...
22
22
  $ juo (--version)
23
- juo/0.1.0 linux-x64 node-v22.21.0
23
+ juo/0.2.1 linux-x64 node-v22.21.0
24
24
  $ juo --help [COMMAND]
25
25
  USAGE
26
26
  $ juo COMMAND
@@ -31,11 +31,37 @@ USAGE
31
31
  # Commands
32
32
 
33
33
  <!-- commands -->
34
+ * [`juo blocks dev`](#juo-blocks-dev)
34
35
  * [`juo create`](#juo-create)
35
36
  * [`juo generate`](#juo-generate)
36
37
  * [`juo help [COMMAND]`](#juo-help-command)
37
38
  * [`juo publish`](#juo-publish)
38
39
 
40
+ ## `juo blocks dev`
41
+
42
+ Start local block dev server for use with the Juo editor
43
+
44
+ ```
45
+ USAGE
46
+ $ juo blocks dev [--reconfigure] [-p <value>]
47
+
48
+ FLAGS
49
+ -p, --port=<value> [default: 5174] Port for the local block dev server
50
+
51
+ GLOBAL FLAGS
52
+ --reconfigure Reconfigure settings
53
+
54
+ DESCRIPTION
55
+ Start local block dev server for use with the Juo editor
56
+
57
+ EXAMPLES
58
+ $ juo blocks dev
59
+ Start dev server on default port (5174).
60
+
61
+ $ juo blocks dev --port 3000
62
+ Start dev server on port 3000.
63
+ ```
64
+
39
65
  ## `juo create`
40
66
 
41
67
  Generate a new Juo project
@@ -0,0 +1,28 @@
1
+ import { Command, Interfaces } from "@oclif/core";
2
+
3
+ //#region src/base-command.d.ts
4
+ interface BaseConfig {
5
+ JUO_API_KEY: string;
6
+ JUO_API_URL: string;
7
+ JUO_TENANT_ID?: string;
8
+ }
9
+ type Flags$1<T extends typeof Command> = Interfaces.InferredFlags<(typeof BaseCommand)['baseFlags'] & T['flags']>;
10
+ type Args<T extends typeof Command> = Interfaces.InferredArgs<T['args']>;
11
+ declare abstract class BaseCommand<T extends typeof Command> extends Command {
12
+ static baseFlags: {
13
+ reconfigure: Interfaces.BooleanFlag<boolean>;
14
+ };
15
+ protected args: Args<T>;
16
+ protected flags: Flags$1<T>;
17
+ protected get configFileName(): string;
18
+ protected get configFilePath(): string;
19
+ protected configExists(): boolean;
20
+ protected ensureConfig(reconfigure?: boolean): Promise<BaseConfig>;
21
+ protected ensureTenantId(): Promise<string>;
22
+ init(): Promise<void>;
23
+ protected loadConfig(): Partial<BaseConfig>;
24
+ protected saveConfig(config: Partial<BaseConfig>): void;
25
+ protected validateConfig(config: Partial<BaseConfig>): config is BaseConfig;
26
+ }
27
+ //#endregion
28
+ export { BaseCommand as t };
@@ -0,0 +1,115 @@
1
+ import { Command, Flags } from "@oclif/core";
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import inquirer from "inquirer";
5
+
6
+ //#region src/base-command.ts
7
+ var BaseCommand = class extends Command {
8
+ static baseFlags = { reconfigure: Flags.boolean({
9
+ default: false,
10
+ description: "Reconfigure settings",
11
+ helpGroup: "GLOBAL"
12
+ }) };
13
+ args;
14
+ flags;
15
+ get configFileName() {
16
+ return "config.json";
17
+ }
18
+ get configFilePath() {
19
+ return path.join(this.config.configDir, this.configFileName);
20
+ }
21
+ configExists() {
22
+ return fs.existsSync(this.configFilePath);
23
+ }
24
+ async ensureConfig(reconfigure = false) {
25
+ let config = {};
26
+ if (this.configExists()) try {
27
+ config = this.loadConfig();
28
+ if (this.validateConfig(config) && !reconfigure) {
29
+ this.log(`Found configuration at ${this.configFilePath}`);
30
+ return config;
31
+ }
32
+ } catch {
33
+ this.log(`Warning: Could not parse existing config at ${this.configFilePath}`);
34
+ }
35
+ if (reconfigure && this.validateConfig(config)) this.log("Reconfiguring settings...");
36
+ else this.log("Configuration incomplete. Setting up...");
37
+ const questions = [];
38
+ if (!config.JUO_API_URL || reconfigure) questions.push({
39
+ default: "https://api.juo.io",
40
+ message: "Enter the Juo API URL:",
41
+ name: "JUO_API_URL",
42
+ type: "input",
43
+ validate(input) {
44
+ if (!input.trim()) return "Juo API URL is required";
45
+ return true;
46
+ }
47
+ });
48
+ if (!config.JUO_API_KEY || reconfigure) questions.push({
49
+ message: "Enter your Juo API key:",
50
+ name: "JUO_API_KEY",
51
+ type: "password",
52
+ validate(input) {
53
+ if (!input.trim()) return "Juo API key is required";
54
+ return true;
55
+ }
56
+ });
57
+ if (questions.length === 0) return config;
58
+ const response = await inquirer.prompt(questions);
59
+ if (response.JUO_API_URL) config.JUO_API_URL = response.JUO_API_URL.trim();
60
+ if (response.JUO_API_KEY) config.JUO_API_KEY = response.JUO_API_KEY.trim();
61
+ this.saveConfig(config);
62
+ this.log(`Saved configuration to ${this.configFilePath}`);
63
+ if (this.validateConfig(config)) return config;
64
+ throw new Error("Failed to create valid configuration");
65
+ }
66
+ async ensureTenantId() {
67
+ let config = {};
68
+ if (this.configExists()) try {
69
+ config = this.loadConfig();
70
+ if (config.JUO_TENANT_ID?.trim()) return config.JUO_TENANT_ID.trim();
71
+ } catch {}
72
+ const tenantId = (await inquirer.prompt([{
73
+ message: "Enter your tenant ID (shop identifier):",
74
+ name: "JUO_TENANT_ID",
75
+ type: "input",
76
+ validate(input) {
77
+ if (!input.trim()) return "Tenant ID is required";
78
+ return true;
79
+ }
80
+ }])).JUO_TENANT_ID.trim().replace(/\.myshopify\.com$/, "");
81
+ config.JUO_TENANT_ID = tenantId;
82
+ this.saveConfig(config);
83
+ return tenantId;
84
+ }
85
+ async init() {
86
+ await super.init();
87
+ const { args, flags } = await this.parse({
88
+ args: this.ctor.args,
89
+ baseFlags: super.ctor.baseFlags,
90
+ flags: this.ctor.flags,
91
+ strict: this.ctor.strict
92
+ });
93
+ this.flags = flags;
94
+ this.args = args;
95
+ }
96
+ loadConfig() {
97
+ if (!this.configExists()) throw new Error(`Configuration file not found at ${this.configFilePath}`);
98
+ try {
99
+ const configContent = fs.readFileSync(this.configFilePath, "utf8");
100
+ return JSON.parse(configContent);
101
+ } catch (error) {
102
+ throw new Error(`Failed to parse configuration file at ${this.configFilePath}: ${error}`);
103
+ }
104
+ }
105
+ saveConfig(config) {
106
+ fs.mkdirSync(this.config.configDir, { recursive: true });
107
+ fs.writeFileSync(this.configFilePath, JSON.stringify(config, null, 2), { encoding: "utf8" });
108
+ }
109
+ validateConfig(config) {
110
+ return Boolean(config.JUO_API_KEY && config.JUO_API_KEY.trim().length > 0 && config.JUO_API_URL && config.JUO_API_URL.trim().length > 0);
111
+ }
112
+ };
113
+
114
+ //#endregion
115
+ export { BaseCommand as t };
@@ -0,0 +1,16 @@
1
+ import { t as BaseCommand } from "../../base-command-BQVnm_gK.js";
2
+ import * as _oclif_core_interfaces10 from "@oclif/core/interfaces";
3
+
4
+ //#region src/commands/blocks/dev.d.ts
5
+ declare class Dev extends BaseCommand<typeof Dev> {
6
+ static description: string;
7
+ static examples: string[];
8
+ static flags: {
9
+ port: _oclif_core_interfaces10.OptionFlag<number, _oclif_core_interfaces10.CustomOptions>;
10
+ };
11
+ run(): Promise<void>;
12
+ private resolvePackageJsonPath;
13
+ private waitForFile;
14
+ }
15
+ //#endregion
16
+ export { Dev as default };
@@ -0,0 +1,91 @@
1
+ import { t as BaseCommand } from "../../base-command-CqPEFZ4E.js";
2
+ import { Flags } from "@oclif/core";
3
+ import { existsSync } from "node:fs";
4
+ import path from "node:path";
5
+ import { spawn } from "node:child_process";
6
+
7
+ //#region src/commands/blocks/dev.ts
8
+ var Dev = class Dev extends BaseCommand {
9
+ static description = "Start local block dev server for use with the Juo editor";
10
+ static examples = [`<%= config.bin %> <%= command.id %>
11
+ Start dev server on default port (5174).
12
+ `, `<%= config.bin %> <%= command.id %> --port 3000
13
+ Start dev server on port 3000.
14
+ `];
15
+ static flags = { port: Flags.integer({
16
+ char: "p",
17
+ default: 5174,
18
+ description: "Port for the local block dev server"
19
+ }) };
20
+ async run() {
21
+ const { flags } = await this.parse(Dev);
22
+ const { port } = flags;
23
+ const rootDir = this.resolvePackageJsonPath();
24
+ const tenantId = await this.ensureTenantId();
25
+ const devBlocksUrl = `http://localhost:${port}/index.js`;
26
+ const editorUrl = `https://admin.juo.io/store/${encodeURIComponent(tenantId)}/editor?dev-blocks-url=${encodeURIComponent(devBlocksUrl)}`;
27
+ this.log(`\nStarting Juo Blocks dev server...`);
28
+ this.log(`\n Open the editor to preview your blocks:`);
29
+ this.log(` ${editorUrl}`);
30
+ this.log(`\n Dev server running on http://localhost:${port}\n`);
31
+ const viteBuild = spawn("npx", [
32
+ "vite",
33
+ "build",
34
+ "--watch"
35
+ ], {
36
+ cwd: rootDir,
37
+ shell: true,
38
+ stdio: "inherit"
39
+ });
40
+ viteBuild.on("error", (err) => {
41
+ this.error(`Failed to start vite build: ${err.message}`);
42
+ });
43
+ const distFile = path.join(rootDir, "dist", "index.js");
44
+ await this.waitForFile(distFile);
45
+ const vitePreview = spawn("npx", [
46
+ "vite",
47
+ "preview",
48
+ "--port",
49
+ String(port)
50
+ ], {
51
+ cwd: rootDir,
52
+ shell: true,
53
+ stdio: "inherit"
54
+ });
55
+ vitePreview.on("error", (err) => {
56
+ this.error(`Failed to start vite preview: ${err.message}`);
57
+ });
58
+ this.log(`\nDev server ready. Press Ctrl+C to stop.\n`);
59
+ const cleanup = () => {
60
+ viteBuild.kill();
61
+ vitePreview.kill();
62
+ process.exit(0);
63
+ };
64
+ process.on("SIGINT", cleanup);
65
+ process.on("SIGTERM", cleanup);
66
+ await new Promise(() => {});
67
+ }
68
+ resolvePackageJsonPath() {
69
+ let currentPath = path.resolve("./");
70
+ while (!existsSync(path.join(currentPath, "package.json"))) {
71
+ const parentDir = path.dirname(currentPath);
72
+ if (parentDir === currentPath) throw new Error("Could not find 'package.json' in the project");
73
+ currentPath = parentDir;
74
+ }
75
+ return currentPath;
76
+ }
77
+ async waitForFile(filePath, timeout = 3e4) {
78
+ const interval = 200;
79
+ let waited = 0;
80
+ while (!existsSync(filePath) && waited < timeout) {
81
+ await new Promise((resolve) => {
82
+ setTimeout(resolve, interval);
83
+ });
84
+ waited += interval;
85
+ }
86
+ if (!existsSync(filePath)) this.error(`Timed out waiting for ${filePath}`);
87
+ }
88
+ };
89
+
90
+ //#endregion
91
+ export { Dev as default };
@@ -1,13 +1,13 @@
1
1
  import { Command } from "@oclif/core";
2
- import * as _oclif_core_interfaces7 from "@oclif/core/interfaces";
2
+ import * as _oclif_core_interfaces5 from "@oclif/core/interfaces";
3
3
 
4
4
  //#region src/commands/create.d.ts
5
5
  declare class Create extends Command {
6
6
  static description: string;
7
7
  static flags: {
8
- quickstart: _oclif_core_interfaces7.BooleanFlag<boolean>;
9
- storybook: _oclif_core_interfaces7.BooleanFlag<boolean>;
10
- verbose: _oclif_core_interfaces7.BooleanFlag<boolean>;
8
+ quickstart: _oclif_core_interfaces5.BooleanFlag<boolean>;
9
+ storybook: _oclif_core_interfaces5.BooleanFlag<boolean>;
10
+ verbose: _oclif_core_interfaces5.BooleanFlag<boolean>;
11
11
  };
12
12
  run(): Promise<void>;
13
13
  private getProjectConfig;
@@ -1,6 +1,6 @@
1
- import { r as BaseTemplateGenerator } from "../juoTemplateGenerator-MZ8llr7w.js";
2
- import { t as PackageGenerator } from "../packageGenerator-Dno-ecHh.js";
3
- import { t as Generate } from "../generate-vpUPJZRH.js";
1
+ import { r as BaseTemplateGenerator } from "../juoTemplateGenerator-Bsxy3cfd.js";
2
+ import { t as PackageGenerator } from "../packageGenerator-BiEzLxCa.js";
3
+ import { t as Generate } from "../generate-CUst3S4-.js";
4
4
  import { Command, Flags } from "@oclif/core";
5
5
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
6
6
  import path from "node:path";
@@ -1,4 +1,4 @@
1
- import "../juoTemplateGenerator-MZ8llr7w.js";
2
- import { t as Generate } from "../generate-vpUPJZRH.js";
1
+ import "../juoTemplateGenerator-Bsxy3cfd.js";
2
+ import { t as Generate } from "../generate-CUst3S4-.js";
3
3
 
4
4
  export { Generate as default };
@@ -1,36 +1,13 @@
1
- import { Command, Interfaces } from "@oclif/core";
2
- import * as _oclif_core_interfaces5 from "@oclif/core/interfaces";
1
+ import { t as BaseCommand } from "../../base-command-BQVnm_gK.js";
2
+ import * as _oclif_core_interfaces8 from "@oclif/core/interfaces";
3
3
 
4
- //#region src/base-command.d.ts
5
- interface BaseConfig {
6
- JUO_API_KEY: string;
7
- JUO_API_URL: string;
8
- }
9
- type Flags$1<T extends typeof Command> = Interfaces.InferredFlags<(typeof BaseCommand)['baseFlags'] & T['flags']>;
10
- type Args<T extends typeof Command> = Interfaces.InferredArgs<T['args']>;
11
- declare abstract class BaseCommand<T extends typeof Command> extends Command {
12
- static baseFlags: {
13
- reconfigure: Interfaces.BooleanFlag<boolean>;
14
- };
15
- protected args: Args<T>;
16
- protected flags: Flags$1<T>;
17
- protected get configFileName(): string;
18
- protected get configFilePath(): string;
19
- protected configExists(): boolean;
20
- protected ensureConfig(reconfigure?: boolean): Promise<BaseConfig>;
21
- init(): Promise<void>;
22
- protected loadConfig(): Partial<BaseConfig>;
23
- protected saveConfig(config: Partial<BaseConfig>): void;
24
- protected validateConfig(config: Partial<BaseConfig>): config is BaseConfig;
25
- }
26
- //#endregion
27
4
  //#region src/commands/publish/index.d.ts
28
5
  declare class Publish extends BaseCommand<typeof Publish> {
29
6
  static args: {};
30
7
  static description: string;
31
8
  static examples: string[];
32
9
  static flags: {
33
- theme: _oclif_core_interfaces5.OptionFlag<string, _oclif_core_interfaces5.CustomOptions>;
10
+ theme: _oclif_core_interfaces8.OptionFlag<string, _oclif_core_interfaces8.CustomOptions>;
34
11
  };
35
12
  getAllFiles(dirPath: string, basePath: string): string[];
36
13
  run(): Promise<void>;
@@ -1,101 +1,11 @@
1
- import { Command, Flags } from "@oclif/core";
1
+ import { t as BaseCommand } from "../../base-command-CqPEFZ4E.js";
2
+ import { Flags } from "@oclif/core";
2
3
  import fs from "node:fs";
3
4
  import path from "node:path";
4
5
  import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
5
6
  import mime from "mime";
6
7
  import asyncPool from "tiny-async-pool";
7
- import inquirer from "inquirer";
8
8
 
9
- //#region src/base-command.ts
10
- var BaseCommand = class extends Command {
11
- static baseFlags = { reconfigure: Flags.boolean({
12
- default: false,
13
- description: "Reconfigure settings",
14
- helpGroup: "GLOBAL"
15
- }) };
16
- args;
17
- flags;
18
- get configFileName() {
19
- return "config.json";
20
- }
21
- get configFilePath() {
22
- return path.join(this.config.configDir, this.configFileName);
23
- }
24
- configExists() {
25
- return fs.existsSync(this.configFilePath);
26
- }
27
- async ensureConfig(reconfigure = false) {
28
- let config = {};
29
- if (this.configExists()) try {
30
- config = this.loadConfig();
31
- if (this.validateConfig(config) && !reconfigure) {
32
- this.log(`Found configuration at ${this.configFilePath}`);
33
- return config;
34
- }
35
- } catch {
36
- this.log(`Warning: Could not parse existing config at ${this.configFilePath}`);
37
- }
38
- if (reconfigure && this.validateConfig(config)) this.log("Reconfiguring settings...");
39
- else this.log("Configuration incomplete. Setting up...");
40
- const questions = [];
41
- if (!config.JUO_API_URL || reconfigure) questions.push({
42
- default: "https://api.juo.io",
43
- message: "Enter the Juo API URL:",
44
- name: "JUO_API_URL",
45
- type: "input",
46
- validate(input) {
47
- if (!input.trim()) return "Juo API URL is required";
48
- return true;
49
- }
50
- });
51
- if (!config.JUO_API_KEY || reconfigure) questions.push({
52
- message: "Enter your Juo API key:",
53
- name: "JUO_API_KEY",
54
- type: "password",
55
- validate(input) {
56
- if (!input.trim()) return "Juo API key is required";
57
- return true;
58
- }
59
- });
60
- if (questions.length === 0) return config;
61
- const response = await inquirer.prompt(questions);
62
- if (response.JUO_API_URL) config.JUO_API_URL = response.JUO_API_URL.trim();
63
- if (response.JUO_API_KEY) config.JUO_API_KEY = response.JUO_API_KEY.trim();
64
- this.saveConfig(config);
65
- this.log(`Saved configuration to ${this.configFilePath}`);
66
- if (this.validateConfig(config)) return config;
67
- throw new Error("Failed to create valid configuration");
68
- }
69
- async init() {
70
- await super.init();
71
- const { args, flags } = await this.parse({
72
- args: this.ctor.args,
73
- baseFlags: super.ctor.baseFlags,
74
- flags: this.ctor.flags,
75
- strict: this.ctor.strict
76
- });
77
- this.flags = flags;
78
- this.args = args;
79
- }
80
- loadConfig() {
81
- if (!this.configExists()) throw new Error(`Configuration file not found at ${this.configFilePath}`);
82
- try {
83
- const configContent = fs.readFileSync(this.configFilePath, "utf8");
84
- return JSON.parse(configContent);
85
- } catch (error) {
86
- throw new Error(`Failed to parse configuration file at ${this.configFilePath}: ${error}`);
87
- }
88
- }
89
- saveConfig(config) {
90
- fs.mkdirSync(this.config.configDir, { recursive: true });
91
- fs.writeFileSync(this.configFilePath, JSON.stringify(config, null, 2), { encoding: "utf8" });
92
- }
93
- validateConfig(config) {
94
- return Boolean(config.JUO_API_KEY && config.JUO_API_KEY.trim().length > 0 && config.JUO_API_URL && config.JUO_API_URL.trim().length > 0);
95
- }
96
- };
97
-
98
- //#endregion
99
9
  //#region src/commands/publish/index.ts
100
10
  var Publish = class extends BaseCommand {
101
11
  static args = {};
@@ -1,4 +1,4 @@
1
- import { t as JuoTemplateGenerator } from "./juoTemplateGenerator-MZ8llr7w.js";
1
+ import { t as JuoTemplateGenerator } from "./juoTemplateGenerator-Bsxy3cfd.js";
2
2
  import { Command, Flags } from "@oclif/core";
3
3
  import { existsSync } from "node:fs";
4
4
  import path from "node:path";
@@ -1,4 +1,4 @@
1
- import { a as CUSTOMERIO_BETA_FORM_URL, i as CUSTOMERIO_API_KEY, n as trackCommandCompleted, o as CUSTOMERIO_SITE_ID, t as trackBetaSignup } from "../analytics-CgHTVQWO.js";
1
+ import { a as CUSTOMERIO_BETA_FORM_URL, i as CUSTOMERIO_API_KEY, n as trackCommandCompleted, o as CUSTOMERIO_SITE_ID, t as trackBetaSignup } from "../analytics-BMClHCkY.js";
2
2
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
3
3
  import path from "node:path";
4
4
  import { confirm, isCancel, text } from "@clack/prompts";
@@ -1,4 +1,4 @@
1
- import { r as trackCommandStarted } from "../analytics-CgHTVQWO.js";
1
+ import { r as trackCommandStarted } from "../analytics-BMClHCkY.js";
2
2
 
3
3
  //#region src/hooks/prerun.ts
4
4
  const hook = async function(options) {
@@ -104,6 +104,7 @@ var JuoTemplateGenerator = class extends BaseTemplateGenerator {
104
104
  options.logger?.("Adding block to theme");
105
105
  try {
106
106
  appendFileSync(path.join(destDir, "index.ts"), `export { ${scope.block.clsName}Block } from "./${scope.block.slug}";\n`);
107
+ this.regenerateRegisterFile(destDir);
107
108
  } catch (error) {
108
109
  options.logger?.("Error adding block to theme: " + error);
109
110
  throw error;
@@ -124,6 +125,36 @@ var JuoTemplateGenerator = class extends BaseTemplateGenerator {
124
125
  }
125
126
  } else options.logger?.(`Story generation skipped (options.story = ${options.story})`);
126
127
  }
128
+ /**
129
+ * Reads the current index.ts to extract all exported block names,
130
+ * then regenerates register.ts with a registerBlocks() function that
131
+ * registers each block via registerBlock() from @juo/blocks.
132
+ */
133
+ regenerateRegisterFile(blocksDir) {
134
+ const indexPath = path.join(blocksDir, "index.ts");
135
+ if (!existsSync(indexPath)) return;
136
+ const indexContent = readFileSync(indexPath, "utf8");
137
+ const exportRegex = /export\s*\{\s*(\w+)\s*\}\s*from\s*["']\.\/([^"']+)["']/g;
138
+ const exports = [];
139
+ let match;
140
+ while ((match = exportRegex.exec(indexContent)) !== null) exports.push({
141
+ name: match[1],
142
+ slug: match[2]
143
+ });
144
+ if (exports.length === 0) return;
145
+ const registerContent = [
146
+ `import { registerBlock } from "@juo/blocks";`,
147
+ exports.map(({ name, slug }) => `import { ${name} } from "./${slug}";`).join("\n"),
148
+ "",
149
+ `export function registerBlocks() {`,
150
+ exports.map(({ name }) => ` registerBlock(${name});`).join("\n"),
151
+ `}`,
152
+ "",
153
+ `export * from "./index";`,
154
+ ""
155
+ ].join("\n");
156
+ writeFileSync(path.join(blocksDir, "register.ts"), registerContent, "utf8");
157
+ }
127
158
  };
128
159
 
129
160
  //#endregion
@@ -33,6 +33,12 @@ declare class JuoTemplateGenerator extends BaseTemplateGenerator {
33
33
  appendStylesheet(destDir: string): void;
34
34
  generate(destDir: string, options: JuoBlockTemplateGeneratorOptions): Promise<void>;
35
35
  private generateBlockTemplate;
36
+ /**
37
+ * Reads the current index.ts to extract all exported block names,
38
+ * then regenerates register.ts with a registerBlocks() function that
39
+ * registers each block via registerBlock() from @juo/blocks.
40
+ */
41
+ private regenerateRegisterFile;
36
42
  }
37
43
  //#endregion
38
44
  //#region src/utils/packageGenerator.d.ts
package/dist/lib/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { n as StoryGenerator, r as BaseTemplateGenerator, t as JuoTemplateGenerator } from "../juoTemplateGenerator-MZ8llr7w.js";
2
- import { t as PackageGenerator } from "../packageGenerator-Dno-ecHh.js";
1
+ import { n as StoryGenerator, r as BaseTemplateGenerator, t as JuoTemplateGenerator } from "../juoTemplateGenerator-Bsxy3cfd.js";
2
+ import { t as PackageGenerator } from "../packageGenerator-BiEzLxCa.js";
3
3
 
4
4
  export { BaseTemplateGenerator, JuoTemplateGenerator, PackageGenerator, StoryGenerator };
@@ -93,6 +93,48 @@
93
93
  "generate.js"
94
94
  ]
95
95
  },
96
+ "blocks:dev": {
97
+ "aliases": [],
98
+ "args": {},
99
+ "description": "Start local block dev server for use with the Juo editor",
100
+ "examples": [
101
+ "<%= config.bin %> <%= command.id %>\nStart dev server on default port (5174).\n",
102
+ "<%= config.bin %> <%= command.id %> --port 3000\nStart dev server on port 3000.\n"
103
+ ],
104
+ "flags": {
105
+ "reconfigure": {
106
+ "description": "Reconfigure settings",
107
+ "helpGroup": "GLOBAL",
108
+ "name": "reconfigure",
109
+ "allowNo": false,
110
+ "type": "boolean"
111
+ },
112
+ "port": {
113
+ "char": "p",
114
+ "description": "Port for the local block dev server",
115
+ "name": "port",
116
+ "default": 5174,
117
+ "hasDynamicHelp": false,
118
+ "multiple": false,
119
+ "type": "option"
120
+ }
121
+ },
122
+ "hasDynamicHelp": false,
123
+ "hiddenAliases": [],
124
+ "id": "blocks:dev",
125
+ "pluginAlias": "juo",
126
+ "pluginName": "juo",
127
+ "pluginType": "core",
128
+ "strict": true,
129
+ "enableJsonFlag": false,
130
+ "isESM": true,
131
+ "relativePath": [
132
+ "dist",
133
+ "commands",
134
+ "blocks",
135
+ "dev.js"
136
+ ]
137
+ },
96
138
  "publish": {
97
139
  "aliases": [],
98
140
  "args": {},
@@ -137,5 +179,5 @@
137
179
  ]
138
180
  }
139
181
  },
140
- "version": "0.1.0"
182
+ "version": "0.2.1"
141
183
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "juo",
3
3
  "description": "A CLI tool for the Juo platform",
4
- "version": "0.1.0",
4
+ "version": "0.2.1",
5
5
  "author": "Juo (https://juo.io)",
6
6
  "bin": {
7
7
  "juo": "./bin/run.js"
@@ -74,6 +74,9 @@
74
74
  },
75
75
  "topicSeparator": " ",
76
76
  "topics": {
77
+ "blocks": {
78
+ "description": "Commands for blocks development"
79
+ },
77
80
  "publish": {
78
81
  "description": "Publish theme files"
79
82
  }
@@ -0,0 +1,33 @@
1
+ import { defineConfig } from "vite";
2
+ import svgr from "vite-plugin-svgr";
3
+ {% if framework == "react" %}
4
+ import react from "@vitejs/plugin-react";
5
+ {% elsif framework == "preact" %}
6
+ import preact from "@preact/preset-vite";
7
+ {% endif %}
8
+
9
+ export default defineConfig({
10
+ define: {
11
+ "process.env.NODE_ENV": JSON.stringify(process.env.NODE_ENV),
12
+ },
13
+ plugins: [{% if framework == "react" %}react(), {% endif %}{% if framework == "preact" %}preact(), {% endif %}
14
+ svgr({
15
+ svgrOptions: {
16
+ icon: true,
17
+ },
18
+ }),
19
+ ],
20
+ preview: {
21
+ cors: true,
22
+ },
23
+ build: {
24
+ lib: {
25
+ entry: "src/blocks/register.ts",
26
+ formats: ["es"],
27
+ fileName: "index",
28
+ },
29
+ rollupOptions: {
30
+ external: ["@juo/blocks"],
31
+ },
32
+ },
33
+ });
@@ -8,6 +8,9 @@ import preact from "@preact/preset-vite";
8
8
  {% endif %}
9
9
 
10
10
  export default defineConfig({
11
+ define: {
12
+ "process.env.NODE_ENV": JSON.stringify(process.env.NODE_ENV),
13
+ },
11
14
  plugins: [tailwindcss(){% if framework == "react" %}, react(){% endif %}{% if framework == "preact" %}, preact(){% endif %},
12
15
  svgr({
13
16
  svgrOptions: {
@@ -15,19 +18,17 @@ export default defineConfig({
15
18
  },
16
19
  }),
17
20
  ],
21
+ preview: {
22
+ cors: true,
23
+ },
18
24
  build: {
19
25
  lib: {
20
- entry: "src/blocks/index.ts",
26
+ entry: "src/blocks/register.ts",
21
27
  formats: ["es"],
22
28
  fileName: "index",
23
29
  },
24
30
  rollupOptions: {
25
- external: [
26
- "@juo/blocks",
27
- "react",
28
- "react-dom",
29
- "preact",
30
- ],
31
+ external: ["@juo/blocks"],
31
32
  },
32
33
  },
33
34
  });