@ikas/component-cli 1.4.0-beta.21 → 1.4.0-beta.212
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/dist/build-tools.d.ts +37 -0
- package/dist/build-tools.d.ts.map +1 -0
- package/dist/build-tools.js +36 -0
- package/dist/build-tools.js.map +1 -0
- package/dist/commands/add-sections-to-page.d.ts +3 -0
- package/dist/commands/add-sections-to-page.d.ts.map +1 -0
- package/dist/commands/add-sections-to-page.js +39 -0
- package/dist/commands/add-sections-to-page.js.map +1 -0
- package/dist/commands/add.d.ts.map +1 -1
- package/dist/commands/add.js +11 -2
- package/dist/commands/add.js.map +1 -1
- package/dist/commands/build.d.ts.map +1 -1
- package/dist/commands/build.js +5 -165
- package/dist/commands/build.js.map +1 -1
- package/dist/commands/config.d.ts +35 -0
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +1082 -147
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/create-design-tokens.d.ts +24 -0
- package/dist/commands/create-design-tokens.d.ts.map +1 -0
- package/dist/commands/create-design-tokens.js +388 -0
- package/dist/commands/create-design-tokens.js.map +1 -0
- package/dist/commands/create-global-variable.d.ts +3 -0
- package/dist/commands/create-global-variable.d.ts.map +1 -0
- package/dist/commands/create-global-variable.js +73 -0
- package/dist/commands/create-global-variable.js.map +1 -0
- package/dist/commands/create-page.d.ts +3 -0
- package/dist/commands/create-page.d.ts.map +1 -0
- package/dist/commands/create-page.js +31 -0
- package/dist/commands/create-page.js.map +1 -0
- package/dist/commands/delete-page.d.ts +3 -0
- package/dist/commands/delete-page.d.ts.map +1 -0
- package/dist/commands/delete-page.js +28 -0
- package/dist/commands/delete-page.js.map +1 -0
- package/dist/commands/delete-theme-globals.d.ts +4 -0
- package/dist/commands/delete-theme-globals.d.ts.map +1 -0
- package/dist/commands/delete-theme-globals.js +48 -0
- package/dist/commands/delete-theme-globals.js.map +1 -0
- package/dist/commands/dev.d.ts.map +1 -1
- package/dist/commands/dev.js +218 -31
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/enable-builtin-pages.d.ts +3 -0
- package/dist/commands/enable-builtin-pages.d.ts.map +1 -0
- package/dist/commands/enable-builtin-pages.js +27 -0
- package/dist/commands/enable-builtin-pages.js.map +1 -0
- package/dist/commands/get-component-props.d.ts +3 -0
- package/dist/commands/get-component-props.d.ts.map +1 -0
- package/dist/commands/get-component-props.js +32 -0
- package/dist/commands/get-component-props.js.map +1 -0
- package/dist/commands/get-page-by-type.d.ts +3 -0
- package/dist/commands/get-page-by-type.d.ts.map +1 -0
- package/dist/commands/get-page-by-type.js +25 -0
- package/dist/commands/get-page-by-type.js.map +1 -0
- package/dist/commands/get-section-values.d.ts +3 -0
- package/dist/commands/get-section-values.d.ts.map +1 -0
- package/dist/commands/get-section-values.js +39 -0
- package/dist/commands/get-section-values.js.map +1 -0
- package/dist/commands/list-builtin-pages.d.ts +3 -0
- package/dist/commands/list-builtin-pages.d.ts.map +1 -0
- package/dist/commands/list-builtin-pages.js +28 -0
- package/dist/commands/list-builtin-pages.js.map +1 -0
- package/dist/commands/list-entities.d.ts +3 -0
- package/dist/commands/list-entities.d.ts.map +1 -0
- package/dist/commands/list-entities.js +32 -0
- package/dist/commands/list-entities.js.map +1 -0
- package/dist/commands/list-page-sections.d.ts.map +1 -1
- package/dist/commands/list-page-sections.js +8 -2
- package/dist/commands/list-page-sections.js.map +1 -1
- package/dist/commands/list-theme-globals.d.ts +3 -0
- package/dist/commands/list-theme-globals.d.ts.map +1 -0
- package/dist/commands/list-theme-globals.js +22 -0
- package/dist/commands/list-theme-globals.js.map +1 -0
- package/dist/commands/move-page-section.d.ts +3 -0
- package/dist/commands/move-page-section.d.ts.map +1 -0
- package/dist/commands/move-page-section.js +62 -0
- package/dist/commands/move-page-section.js.map +1 -0
- package/dist/commands/publish-theme.d.ts +3 -0
- package/dist/commands/publish-theme.d.ts.map +1 -0
- package/dist/commands/publish-theme.js +29 -0
- package/dist/commands/publish-theme.js.map +1 -0
- package/dist/commands/publish.d.ts.map +1 -1
- package/dist/commands/publish.js +54 -3
- package/dist/commands/publish.js.map +1 -1
- package/dist/commands/remove-page-section.d.ts +3 -0
- package/dist/commands/remove-page-section.d.ts.map +1 -0
- package/dist/commands/remove-page-section.js +40 -0
- package/dist/commands/remove-page-section.js.map +1 -0
- package/dist/commands/search-products.d.ts +3 -0
- package/dist/commands/search-products.d.ts.map +1 -0
- package/dist/commands/search-products.js +40 -0
- package/dist/commands/search-products.js.map +1 -0
- package/dist/commands/update-builtin-page-prop.d.ts +3 -0
- package/dist/commands/update-builtin-page-prop.d.ts.map +1 -0
- package/dist/commands/update-builtin-page-prop.js +49 -0
- package/dist/commands/update-builtin-page-prop.js.map +1 -0
- package/dist/commands/update-global-variable.d.ts +3 -0
- package/dist/commands/update-global-variable.d.ts.map +1 -0
- package/dist/commands/update-global-variable.js +70 -0
- package/dist/commands/update-global-variable.js.map +1 -0
- package/dist/commands/update-page-sections.d.ts +3 -0
- package/dist/commands/update-page-sections.d.ts.map +1 -0
- package/dist/commands/update-page-sections.js +39 -0
- package/dist/commands/update-page-sections.js.map +1 -0
- package/dist/commands/update-section-prop.d.ts.map +1 -1
- package/dist/commands/update-section-prop.js +25 -8
- package/dist/commands/update-section-prop.js.map +1 -1
- package/dist/commands/upload-image.d.ts.map +1 -1
- package/dist/commands/upload-image.js +5 -46
- package/dist/commands/upload-image.js.map +1 -1
- package/dist/commands/upload-images.d.ts +3 -0
- package/dist/commands/upload-images.d.ts.map +1 -0
- package/dist/commands/upload-images.js +48 -0
- package/dist/commands/upload-images.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +54 -1
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +51 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/archive-project.d.ts +69 -0
- package/dist/utils/archive-project.d.ts.map +1 -0
- package/dist/utils/archive-project.js +202 -0
- package/dist/utils/archive-project.js.map +1 -0
- package/dist/utils/compile.d.ts +17 -2
- package/dist/utils/compile.d.ts.map +1 -1
- package/dist/utils/compile.js +750 -117
- package/dist/utils/compile.js.map +1 -1
- package/dist/utils/component-helpers.d.ts +167 -2
- package/dist/utils/component-helpers.d.ts.map +1 -1
- package/dist/utils/component-helpers.js +452 -29
- package/dist/utils/component-helpers.js.map +1 -1
- package/dist/utils/css-import-resolver.d.ts +4 -1
- package/dist/utils/css-import-resolver.d.ts.map +1 -1
- package/dist/utils/css-import-resolver.js +9 -1
- package/dist/utils/css-import-resolver.js.map +1 -1
- package/dist/utils/editor-action-client.d.ts +4 -3
- package/dist/utils/editor-action-client.d.ts.map +1 -1
- package/dist/utils/editor-action-client.js +55 -19
- package/dist/utils/editor-action-client.js.map +1 -1
- package/dist/utils/esm-transform.d.ts +30 -0
- package/dist/utils/esm-transform.d.ts.map +1 -1
- package/dist/utils/esm-transform.js +169 -2
- package/dist/utils/esm-transform.js.map +1 -1
- package/dist/utils/find-component-for-file.d.ts +12 -0
- package/dist/utils/find-component-for-file.d.ts.map +1 -0
- package/dist/utils/find-component-for-file.js +24 -0
- package/dist/utils/find-component-for-file.js.map +1 -0
- package/dist/utils/forbid-deep-imports.d.ts +3 -0
- package/dist/utils/forbid-deep-imports.d.ts.map +1 -0
- package/dist/utils/forbid-deep-imports.js +54 -0
- package/dist/utils/forbid-deep-imports.js.map +1 -0
- package/dist/utils/forbid-external-packages.d.ts +26 -0
- package/dist/utils/forbid-external-packages.d.ts.map +1 -0
- package/dist/utils/forbid-external-packages.js +99 -0
- package/dist/utils/forbid-external-packages.js.map +1 -0
- package/dist/utils/load-image.d.ts +16 -0
- package/dist/utils/load-image.d.ts.map +1 -0
- package/dist/utils/load-image.js +50 -0
- package/dist/utils/load-image.js.map +1 -0
- package/dist/utils/vendor-storefront.d.ts +13 -0
- package/dist/utils/vendor-storefront.d.ts.map +1 -0
- package/dist/utils/vendor-storefront.js +91 -0
- package/dist/utils/vendor-storefront.js.map +1 -0
- package/dist/utils/websocket-server.d.ts +119 -5
- package/dist/utils/websocket-server.d.ts.map +1 -1
- package/dist/utils/websocket-server.js +255 -44
- package/dist/utils/websocket-server.js.map +1 -1
- package/package.json +19 -2
- package/templates/add/section.css +11 -0
- package/dist/commands/create.d.ts +0 -4
- package/dist/commands/create.d.ts.map +0 -1
- package/dist/commands/create.js +0 -228
- package/dist/commands/create.js.map +0 -1
- package/dist/commands/proxy.d.ts +0 -39
- package/dist/commands/proxy.d.ts.map +0 -1
- package/dist/commands/proxy.js +0 -210
- package/dist/commands/proxy.js.map +0 -1
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { printErrorAndExit, printResultAndExit, runEditorAction } from "../utils/editor-action-client.js";
|
|
3
|
+
const TOKEN_TYPES = ["color", "typography", "breakpoint", "keyframe", "colorScheme", "colorSchemeSlot"];
|
|
4
|
+
function portOpts(port) {
|
|
5
|
+
const p = port ? parseInt(port, 10) : undefined;
|
|
6
|
+
return p ? { port: p } : {};
|
|
7
|
+
}
|
|
8
|
+
export function createDeleteGlobalVariableCommand() {
|
|
9
|
+
const cmd = new Command("delete-global-variable");
|
|
10
|
+
cmd
|
|
11
|
+
.description("Delete a global variable from the connected editor")
|
|
12
|
+
.requiredOption("--name <key>", "The variable's runtime key (from `list-theme-globals`)")
|
|
13
|
+
.option("--port <port>", "Dev server WebSocket port", "5201")
|
|
14
|
+
.action(async (options) => {
|
|
15
|
+
if (!options.name)
|
|
16
|
+
printErrorAndExit(new Error("--name is required"));
|
|
17
|
+
try {
|
|
18
|
+
printResultAndExit(await runEditorAction("delete-global-variable", { name: options.name }, portOpts(options.port)));
|
|
19
|
+
}
|
|
20
|
+
catch (e) {
|
|
21
|
+
printErrorAndExit(e);
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
return cmd;
|
|
25
|
+
}
|
|
26
|
+
export function createDeleteDesignTokenCommand() {
|
|
27
|
+
const cmd = new Command("delete-design-token");
|
|
28
|
+
cmd
|
|
29
|
+
.description("Delete a design token (color, typography, breakpoint, keyframe, color scheme, or color scheme slot) from the connected editor")
|
|
30
|
+
.requiredOption("--token-type <type>", TOKEN_TYPES.join(" | "))
|
|
31
|
+
.requiredOption("--id <id>", "The token id (from `list-theme-globals`). For colorSchemeSlot use the slot id from colorSchemes.schemes")
|
|
32
|
+
.option("--port <port>", "Dev server WebSocket port", "5201")
|
|
33
|
+
.action(async (options) => {
|
|
34
|
+
if (!options.tokenType || !TOKEN_TYPES.includes(options.tokenType)) {
|
|
35
|
+
printErrorAndExit(new Error(`--token-type must be one of: ${TOKEN_TYPES.join(", ")}`));
|
|
36
|
+
}
|
|
37
|
+
if (!options.id)
|
|
38
|
+
printErrorAndExit(new Error("--id is required"));
|
|
39
|
+
try {
|
|
40
|
+
printResultAndExit(await runEditorAction("delete-design-token", { tokenType: options.tokenType, id: options.id }, portOpts(options.port)));
|
|
41
|
+
}
|
|
42
|
+
catch (e) {
|
|
43
|
+
printErrorAndExit(e);
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
return cmd;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=delete-theme-globals.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delete-theme-globals.js","sourceRoot":"","sources":["../../src/commands/delete-theme-globals.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAE1G,MAAM,WAAW,GAAG,CAAC,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,iBAAiB,CAAC,CAAC;AAExG,SAAS,QAAQ,CAAC,IAAa;IAC7B,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAChD,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;AAC9B,CAAC;AAED,MAAM,UAAU,iCAAiC;IAC/C,MAAM,GAAG,GAAG,IAAI,OAAO,CAAC,wBAAwB,CAAC,CAAC;IAClD,GAAG;SACA,WAAW,CAAC,oDAAoD,CAAC;SACjE,cAAc,CAAC,cAAc,EAAE,wDAAwD,CAAC;SACxF,MAAM,CAAC,eAAe,EAAE,2BAA2B,EAAE,MAAM,CAAC;SAC5D,MAAM,CAAC,KAAK,EAAE,OAAyC,EAAE,EAAE;QAC1D,IAAI,CAAC,OAAO,CAAC,IAAI;YAAE,iBAAiB,CAAC,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC,CAAC;QACtE,IAAI,CAAC;YACH,kBAAkB,CAAC,MAAM,eAAe,CAAC,wBAAwB,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,EAAE,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACtH,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,iBAAiB,CAAC,CAAC,CAAC,CAAC;QACvB,CAAC;IACH,CAAC,CAAC,CAAC;IACL,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,UAAU,8BAA8B;IAC5C,MAAM,GAAG,GAAG,IAAI,OAAO,CAAC,qBAAqB,CAAC,CAAC;IAC/C,GAAG;SACA,WAAW,CAAC,+HAA+H,CAAC;SAC5I,cAAc,CAAC,qBAAqB,EAAE,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;SAC9D,cAAc,CACb,WAAW,EACX,yGAAyG,CAC1G;SACA,MAAM,CAAC,eAAe,EAAE,2BAA2B,EAAE,MAAM,CAAC;SAC5D,MAAM,CAAC,KAAK,EAAE,OAA2D,EAAE,EAAE;QAC5E,IAAI,CAAC,OAAO,CAAC,SAAS,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;YACnE,iBAAiB,CAAC,IAAI,KAAK,CAAC,gCAAgC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;QACzF,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,EAAE;YAAE,iBAAiB,CAAC,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAC,CAAC;QAClE,IAAI,CAAC;YACH,kBAAkB,CAChB,MAAM,eAAe,CACnB,qBAAqB,EACrB,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,EAChD,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CACvB,CACF,CAAC;QACJ,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,iBAAiB,CAAC,CAAC,CAAC,CAAC;QACvB,CAAC;IACH,CAAC,CAAC,CAAC;IACL,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../src/commands/dev.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../src/commands/dev.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAk5DpC,wBAAgB,gBAAgB,IAAI,OAAO,CAI1C"}
|
package/dist/commands/dev.js
CHANGED
|
@@ -4,9 +4,11 @@ import { Command } from "commander";
|
|
|
4
4
|
import * as crypto from "crypto";
|
|
5
5
|
import * as fs from "fs";
|
|
6
6
|
import * as path from "path";
|
|
7
|
-
import { toPascalCase, generateTypesFile, generateGlobalTypesFile, collectUsedEnumIds, collectUsedCustomTypeIds, generateComponentFile, generateStylesFile, updateBarrelExport, generateProjectId, generateComponentId, generateUniqueId, buildPropGroupHierarchy, findPropGroup, collectPropGroupIds, movePropGroupInTree, validateFilteredComponentIds, } from "../utils/component-helpers.js";
|
|
7
|
+
import { toPascalCase, generateTypesFile, generateGlobalTypesFile, collectUsedEnumIds, collectUsedCustomTypeIds, shouldWriteGlobalTypes, generateComponentFile, generateStylesFile, updateBarrelExport, generateProjectId, isValidProjectId, findInvalidComponentIds, findIdentityChanges, COMPONENT_ID_HINT, generateComponentId, generateUniqueId, buildPropGroupHierarchy, propIdsByName, resolveCondition, visibilityGateError, findPropGroup, collectPropGroupIds, movePropGroupInTree, validateFilteredComponentIds, isBuiltInEnumTypeId, } from "../utils/component-helpers.js";
|
|
8
|
+
import { findComponentForFile } from "../utils/find-component-for-file.js";
|
|
9
|
+
import { archiveProject, removeArchive, uploadArchive, } from "../utils/archive-project.js";
|
|
8
10
|
import { compileAllComponents as compileAllComponentsMulti } from "../utils/compile.js";
|
|
9
|
-
import { transformEsmToWindowGlobals, transformChunkForCanvas, buildChunkMapping, } from "../utils/esm-transform.js";
|
|
11
|
+
import { transformEsmToWindowGlobals, transformChunkForCanvas, buildChunkMapping, findComputedDynamicImportsInBundles, } from "../utils/esm-transform.js";
|
|
10
12
|
import { DevServerWebSocket, } from "../utils/websocket-server.js";
|
|
11
13
|
const DEV_SERVER_PORT = 5201;
|
|
12
14
|
// Store compiled components, shared modules, and global styles
|
|
@@ -24,6 +26,9 @@ let lastBroadcastGlobalStyleHash;
|
|
|
24
26
|
let cachedEditorTypes = null;
|
|
25
27
|
// Cached custom type definitions received from the editor via sync-types (full IType objects)
|
|
26
28
|
let cachedCustomTypes = null;
|
|
29
|
+
// Cached theme global variables received from the editor via sync-types.
|
|
30
|
+
// Drives the ThemeSettingName union in src/global-types.ts.
|
|
31
|
+
let cachedThemeSettings = null;
|
|
27
32
|
const LIBRARY_TYPE_PREFIX = "@ikas/";
|
|
28
33
|
/**
|
|
29
34
|
* Match custom types for a component's props from the cached custom types.
|
|
@@ -77,24 +82,6 @@ function matchCustomTypesForProps(props, allCustomTypes) {
|
|
|
77
82
|
}
|
|
78
83
|
return Array.from(collected.values());
|
|
79
84
|
}
|
|
80
|
-
/**
|
|
81
|
-
* Get the component definition that contains a file path
|
|
82
|
-
*/
|
|
83
|
-
function findComponentForFile(config, filePath) {
|
|
84
|
-
const normalizedPath = path.normalize(filePath);
|
|
85
|
-
for (const component of config.components) {
|
|
86
|
-
const entryPath = path.resolve(process.cwd(), component.entry);
|
|
87
|
-
const stylesPath = path.resolve(process.cwd(), component.styles);
|
|
88
|
-
const componentDir = path.dirname(entryPath);
|
|
89
|
-
// Check if the file is the entry, styles, or in the component directory
|
|
90
|
-
if (normalizedPath === entryPath ||
|
|
91
|
-
normalizedPath === stylesPath ||
|
|
92
|
-
normalizedPath.startsWith(componentDir + path.sep)) {
|
|
93
|
-
return component;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
return null;
|
|
97
|
-
}
|
|
98
85
|
/**
|
|
99
86
|
* Compile all components using multi-entry code splitting.
|
|
100
87
|
* Updates compiledComponents and compiledSharedModules maps.
|
|
@@ -136,6 +123,18 @@ async function compileAllComponentsForDev(config) {
|
|
|
136
123
|
if (chunkIds.length > 0) {
|
|
137
124
|
console.log(chalk.cyan(` Extracted ${chunkIds.length} shared chunk(s)`));
|
|
138
125
|
}
|
|
126
|
+
// Nothing downstream can resolve a computed specifier, so it 404s on the first lazy path that
|
|
127
|
+
// reaches it. Same pass `publish` runs, on the same two maps, so the two cannot drift apart —
|
|
128
|
+
// and both only warn for now (see the note in publish.ts on why that gate is not yet an error).
|
|
129
|
+
// Warning here would be right regardless: killing the watch loop over it is worse than a canvas
|
|
130
|
+
// that half-works, and the developer is right here to read the line.
|
|
131
|
+
const computedImports = findComputedDynamicImportsInBundles(result.chunks, result.entries, new Map(config.components.map((c) => [c.id, c.name])));
|
|
132
|
+
if (computedImports.length > 0) {
|
|
133
|
+
console.warn(chalk.yellow(` ${computedImports.length} dynamic import(s) with a computed specifier — these will 404 in the canvas. Use a literal, e.g. import("./thing.js") not import(name):`));
|
|
134
|
+
for (const offender of computedImports) {
|
|
135
|
+
console.warn(chalk.gray(` ${offender}`));
|
|
136
|
+
}
|
|
137
|
+
}
|
|
139
138
|
// Store global CSS (unscoped). Preserve `updatedAt` across rebuilds when the compiled
|
|
140
139
|
// global CSS is byte-identical so the editor only sees a fresh timestamp when the
|
|
141
140
|
// designer actually changed `global.css` — the publish UI watches this timestamp to
|
|
@@ -176,6 +175,12 @@ async function compileAllComponentsForDev(config) {
|
|
|
176
175
|
const canvasClientJs = transformEsmToWindowGlobals(entry.clientJs, {
|
|
177
176
|
chunkMapping,
|
|
178
177
|
});
|
|
178
|
+
// Config names a prop's visibility gate; the editor addresses props by id, so resolve the one
|
|
179
|
+
// against the other off the same index formula the ids come from.
|
|
180
|
+
const propIdByName = propIdsByName(component.props.map((prop, index) => ({
|
|
181
|
+
id: `${component.id}_prop_${index}`,
|
|
182
|
+
name: prop.name,
|
|
183
|
+
})));
|
|
179
184
|
const propsWithIds = component.props.map((prop, index) => ({
|
|
180
185
|
id: `${component.id}_prop_${index}`,
|
|
181
186
|
name: prop.name,
|
|
@@ -187,10 +192,14 @@ async function compileAllComponentsForDev(config) {
|
|
|
187
192
|
groupId: prop.groupId,
|
|
188
193
|
typeId: prop.typeId,
|
|
189
194
|
enumTypeId: prop.enumTypeId,
|
|
195
|
+
...(prop.numberRangeData
|
|
196
|
+
? { numberRangeData: prop.numberRangeData }
|
|
197
|
+
: {}),
|
|
190
198
|
...(prop.privateVarMap ? { privateVarMap: prop.privateVarMap } : {}),
|
|
191
199
|
...(prop.filteredComponentIds
|
|
192
200
|
? { filteredComponentIds: prop.filteredComponentIds }
|
|
193
201
|
: {}),
|
|
202
|
+
...resolveCondition(prop, propIdByName),
|
|
194
203
|
}));
|
|
195
204
|
// Build prop group hierarchy if groups are defined
|
|
196
205
|
const propGroups = component.propGroups && component.propGroups.length > 0
|
|
@@ -200,7 +209,7 @@ async function compileAllComponentsForDev(config) {
|
|
|
200
209
|
const componentCustomTypes = cachedCustomTypes
|
|
201
210
|
? matchCustomTypesForProps(propsWithIds, cachedCustomTypes)
|
|
202
211
|
: undefined;
|
|
203
|
-
const usedSharedModuleIds = (result.entryChunkIds.get(component.id) || []).map((id) => config.projectId ? `${config.projectId}-${id}` : id);
|
|
212
|
+
const usedSharedModuleIds = (result.entryChunkIds.get(component.id) || []).map((id) => (config.projectId ? `${config.projectId}-${id}` : id));
|
|
204
213
|
const data = {
|
|
205
214
|
id: component.id,
|
|
206
215
|
name: component.name,
|
|
@@ -253,6 +262,10 @@ function rebuildCompiledComponentFromConfig(config, componentId) {
|
|
|
253
262
|
const component = config.components.find((c) => c.id === componentId);
|
|
254
263
|
if (!component)
|
|
255
264
|
return null;
|
|
265
|
+
const propIdByName = propIdsByName(component.props.map((prop, index) => ({
|
|
266
|
+
id: `${component.id}_prop_${index}`,
|
|
267
|
+
name: prop.name,
|
|
268
|
+
})));
|
|
256
269
|
const propsWithIds = component.props.map((prop, index) => ({
|
|
257
270
|
id: `${component.id}_prop_${index}`,
|
|
258
271
|
name: prop.name,
|
|
@@ -264,10 +277,12 @@ function rebuildCompiledComponentFromConfig(config, componentId) {
|
|
|
264
277
|
groupId: prop.groupId,
|
|
265
278
|
typeId: prop.typeId,
|
|
266
279
|
enumTypeId: prop.enumTypeId,
|
|
280
|
+
...(prop.numberRangeData ? { numberRangeData: prop.numberRangeData } : {}),
|
|
267
281
|
...(prop.privateVarMap ? { privateVarMap: prop.privateVarMap } : {}),
|
|
268
282
|
...(prop.filteredComponentIds
|
|
269
283
|
? { filteredComponentIds: prop.filteredComponentIds }
|
|
270
284
|
: {}),
|
|
285
|
+
...resolveCondition(prop, propIdByName),
|
|
271
286
|
}));
|
|
272
287
|
const propGroups = component.propGroups && component.propGroups.length > 0
|
|
273
288
|
? buildPropGroupHierarchy(component.id, component.propGroups, propsWithIds)
|
|
@@ -310,7 +325,13 @@ function sha256Hex(input) {
|
|
|
310
325
|
*/
|
|
311
326
|
function populateContentHashes() {
|
|
312
327
|
for (const mod of compiledSharedModules.values()) {
|
|
313
|
-
mod.contentHash = sha256Hex([
|
|
328
|
+
mod.contentHash = sha256Hex([
|
|
329
|
+
mod.id,
|
|
330
|
+
mod.compiledServerJs,
|
|
331
|
+
mod.compiledClientJs,
|
|
332
|
+
mod.canvasClientJs,
|
|
333
|
+
mod.compiledCss,
|
|
334
|
+
].join("\0"));
|
|
314
335
|
}
|
|
315
336
|
for (const comp of compiledComponents.values()) {
|
|
316
337
|
const referencedHashes = (comp.usedSharedModuleIds || [])
|
|
@@ -461,12 +482,20 @@ function writeConfig(configPath, config) {
|
|
|
461
482
|
function writeGlobalTypesFile(config) {
|
|
462
483
|
const globalTypesPath = path.resolve(process.cwd(), "src/global-types.ts");
|
|
463
484
|
const usedEnumIds = collectUsedEnumIds(config.components);
|
|
464
|
-
const content = generateGlobalTypesFile(cachedEditorTypes, cachedCustomTypes, usedEnumIds);
|
|
465
|
-
//
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
485
|
+
const content = generateGlobalTypesFile(cachedEditorTypes, cachedCustomTypes, usedEnumIds, cachedThemeSettings);
|
|
486
|
+
// Single read instead of existsSync + readFileSync; absent file reads as null.
|
|
487
|
+
let existing = null;
|
|
488
|
+
try {
|
|
489
|
+
existing = fs.readFileSync(globalTypesPath, "utf-8");
|
|
490
|
+
}
|
|
491
|
+
catch {
|
|
492
|
+
existing = null;
|
|
493
|
+
}
|
|
494
|
+
// Skip unnecessary writes (file-watcher loops) and, crucially, don't let the
|
|
495
|
+
// startup write clobber editor-synced theme globals before the editor has
|
|
496
|
+
// connected and re-synced them.
|
|
497
|
+
if (!shouldWriteGlobalTypes(existing, content, cachedThemeSettings != null)) {
|
|
498
|
+
return;
|
|
470
499
|
}
|
|
471
500
|
fs.writeFileSync(globalTypesPath, content);
|
|
472
501
|
}
|
|
@@ -502,6 +531,44 @@ function createEditorHandlers(configPath, getConfig, setConfig, wsServer) {
|
|
|
502
531
|
sharedModules: getAllSharedModules(),
|
|
503
532
|
globalStyles: compiledGlobalStyles,
|
|
504
533
|
}),
|
|
534
|
+
// The editor sends this after a partner publishes a new design-asset
|
|
535
|
+
// version: zip this folder without node_modules and PUT it to the
|
|
536
|
+
// presigned URL the ikas backend issued. The working tree is untouched.
|
|
537
|
+
onArchiveProject: async (payload) => {
|
|
538
|
+
const rootDir = process.cwd();
|
|
539
|
+
console.log(chalk.cyan(` Archiving theme source (${rootDir}) without node_modules...`));
|
|
540
|
+
const archive = await archiveProject({
|
|
541
|
+
rootDir,
|
|
542
|
+
exclude: payload.exclude,
|
|
543
|
+
rewriteIds: payload.rewriteIds,
|
|
544
|
+
});
|
|
545
|
+
try {
|
|
546
|
+
let uploaded = false;
|
|
547
|
+
let etag;
|
|
548
|
+
if (payload.uploadUrl) {
|
|
549
|
+
const result = await uploadArchive({
|
|
550
|
+
zipPath: archive.zipPath,
|
|
551
|
+
uploadUrl: payload.uploadUrl,
|
|
552
|
+
method: payload.method,
|
|
553
|
+
headers: payload.headers,
|
|
554
|
+
});
|
|
555
|
+
uploaded = true;
|
|
556
|
+
etag = result.etag;
|
|
557
|
+
}
|
|
558
|
+
console.log(chalk.green(` Theme source archived: ${archive.fileCount} files, ${(archive.size / 1024).toFixed(0)} KB` +
|
|
559
|
+
(uploaded ? " — uploaded" : " — not uploaded (no upload URL)")));
|
|
560
|
+
return {
|
|
561
|
+
rootDir,
|
|
562
|
+
size: archive.size,
|
|
563
|
+
fileCount: archive.fileCount,
|
|
564
|
+
uploaded,
|
|
565
|
+
etag,
|
|
566
|
+
};
|
|
567
|
+
}
|
|
568
|
+
finally {
|
|
569
|
+
removeArchive(archive.zipPath);
|
|
570
|
+
}
|
|
571
|
+
},
|
|
505
572
|
onCreateComponent: async (name, type) => {
|
|
506
573
|
const pascalName = toPascalCase(name);
|
|
507
574
|
// Validate
|
|
@@ -512,6 +579,12 @@ function createEditorHandlers(configPath, getConfig, setConfig, wsServer) {
|
|
|
512
579
|
if (config.components.some((c) => c.name === pascalName)) {
|
|
513
580
|
throw new Error(`Component "${pascalName}" already exists`);
|
|
514
581
|
}
|
|
582
|
+
// No `!` assertion: the config may have been hot-reloaded since startup, and
|
|
583
|
+
// minting with a missing/malformed projectId writes a corrupt component id
|
|
584
|
+
// into ikas.config.json that later publishes verbatim.
|
|
585
|
+
if (!config.projectId || !isValidProjectId(config.projectId)) {
|
|
586
|
+
throw new Error("Invalid or missing projectId in ikas.config.json — restore the generated value and restart the dev server");
|
|
587
|
+
}
|
|
515
588
|
const componentId = generateComponentId(config.projectId);
|
|
516
589
|
const componentDir = path.resolve(process.cwd(), `src/components/${pascalName}`);
|
|
517
590
|
// Create directory and files
|
|
@@ -553,7 +626,7 @@ function createEditorHandlers(configPath, getConfig, setConfig, wsServer) {
|
|
|
553
626
|
if (!prop.enumTypeId) {
|
|
554
627
|
throw new Error(`ENUM prop "${prop.name}" requires enumTypeId. Create one first with "config add-enum".`);
|
|
555
628
|
}
|
|
556
|
-
if (!prop.enumTypeId
|
|
629
|
+
if (!isBuiltInEnumTypeId(prop.enumTypeId)) {
|
|
557
630
|
const customTypes = config.customTypes || [];
|
|
558
631
|
const enumExists = customTypes.some((t) => t.id === prop.enumTypeId && t.type === "enum");
|
|
559
632
|
if (!enumExists) {
|
|
@@ -573,6 +646,9 @@ function createEditorHandlers(configPath, getConfig, setConfig, wsServer) {
|
|
|
573
646
|
`Known components: ${config.components.map((c) => `${c.name} (${c.id})`).join(", ")}.`);
|
|
574
647
|
}
|
|
575
648
|
}
|
|
649
|
+
const addGateError = visibilityGateError(component, prop, `prop "${prop.name}"`, { selfPropName: prop.name });
|
|
650
|
+
if (addGateError)
|
|
651
|
+
throw new Error(addGateError);
|
|
576
652
|
component.props.push(prop);
|
|
577
653
|
writeConfig(configPath, config);
|
|
578
654
|
setConfig(config);
|
|
@@ -601,6 +677,13 @@ function createEditorHandlers(configPath, getConfig, setConfig, wsServer) {
|
|
|
601
677
|
`Known components: ${config.components.map((c) => `${c.name} (${c.id})`).join(", ")}.`);
|
|
602
678
|
}
|
|
603
679
|
}
|
|
680
|
+
// Checked against the component as it will be, not as it is: a gate on the incoming prop can
|
|
681
|
+
// name another prop, and a rename in the same save changes what the chain resolves to.
|
|
682
|
+
const nextProps = component.props.slice();
|
|
683
|
+
nextProps[propIndex] = prop;
|
|
684
|
+
const updateGateError = visibilityGateError({ ...component, props: nextProps }, prop, `prop "${prop.name}"`, { selfPropName: prop.name });
|
|
685
|
+
if (updateGateError)
|
|
686
|
+
throw new Error(updateGateError);
|
|
604
687
|
component.props[propIndex] = prop;
|
|
605
688
|
writeConfig(configPath, config);
|
|
606
689
|
setConfig(config);
|
|
@@ -648,7 +731,21 @@ function createEditorHandlers(configPath, getConfig, setConfig, wsServer) {
|
|
|
648
731
|
...(propGroup.description
|
|
649
732
|
? { description: propGroup.description }
|
|
650
733
|
: {}),
|
|
734
|
+
...(propGroup.requiredProp
|
|
735
|
+
? {
|
|
736
|
+
requiredProp: propGroup.requiredProp,
|
|
737
|
+
...(propGroup.requiredEnumOptionValue !== undefined
|
|
738
|
+
? {
|
|
739
|
+
requiredEnumOptionId: propGroup.requiredEnumOptionId,
|
|
740
|
+
requiredEnumOptionValue: propGroup.requiredEnumOptionValue,
|
|
741
|
+
}
|
|
742
|
+
: { requiredPropValue: propGroup.requiredPropValue ?? true }),
|
|
743
|
+
}
|
|
744
|
+
: {}),
|
|
651
745
|
};
|
|
746
|
+
const gateError = visibilityGateError(component, newGroup, `group "${newGroup.id}"`, { group: newGroup });
|
|
747
|
+
if (gateError)
|
|
748
|
+
throw new Error(gateError);
|
|
652
749
|
if (propGroup.parentGroupId) {
|
|
653
750
|
const found = findPropGroup(component.propGroups, propGroup.parentGroupId);
|
|
654
751
|
if (!found)
|
|
@@ -681,6 +778,32 @@ function createEditorHandlers(configPath, getConfig, setConfig, wsServer) {
|
|
|
681
778
|
found.group.name = updates.name;
|
|
682
779
|
if (updates.description !== undefined)
|
|
683
780
|
found.group.description = updates.description || undefined;
|
|
781
|
+
if (updates.requiredProp !== undefined) {
|
|
782
|
+
if (!updates.requiredProp || updates.requiredProp === "none") {
|
|
783
|
+
// Both go together — a state with no prop behind it would read as a rule.
|
|
784
|
+
delete found.group.requiredProp;
|
|
785
|
+
delete found.group.requiredPropValue;
|
|
786
|
+
delete found.group.requiredEnumOptionId;
|
|
787
|
+
delete found.group.requiredEnumOptionValue;
|
|
788
|
+
}
|
|
789
|
+
else {
|
|
790
|
+
found.group.requiredProp = updates.requiredProp;
|
|
791
|
+
if (updates.requiredEnumOptionValue !== undefined) {
|
|
792
|
+
found.group.requiredEnumOptionId = updates.requiredEnumOptionId;
|
|
793
|
+
found.group.requiredEnumOptionValue =
|
|
794
|
+
updates.requiredEnumOptionValue;
|
|
795
|
+
delete found.group.requiredPropValue;
|
|
796
|
+
}
|
|
797
|
+
else {
|
|
798
|
+
found.group.requiredPropValue = updates.requiredPropValue ?? true;
|
|
799
|
+
delete found.group.requiredEnumOptionId;
|
|
800
|
+
delete found.group.requiredEnumOptionValue;
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
const gateError = visibilityGateError(component, found.group, `group "${found.group.id}"`, { group: found.group });
|
|
805
|
+
if (gateError)
|
|
806
|
+
throw new Error(gateError);
|
|
684
807
|
writeConfig(configPath, config);
|
|
685
808
|
setConfig(config);
|
|
686
809
|
broadcastConfigChange(componentId);
|
|
@@ -871,8 +994,10 @@ function createEditorHandlers(configPath, getConfig, setConfig, wsServer) {
|
|
|
871
994
|
regenerateAllComponentTypes(config);
|
|
872
995
|
console.log(chalk.green(` Deleted enum: ${removed.name} (${enumId})`));
|
|
873
996
|
},
|
|
874
|
-
onSyncTypes: (types, customTypes) => {
|
|
997
|
+
onSyncTypes: (types, customTypes, themeSettings) => {
|
|
875
998
|
cachedEditorTypes = types;
|
|
999
|
+
if (themeSettings)
|
|
1000
|
+
cachedThemeSettings = themeSettings;
|
|
876
1001
|
// Merge incoming custom types with existing ones instead of replacing.
|
|
877
1002
|
// Custom types belong to the code component project and should not be
|
|
878
1003
|
// lost when a different editor project connects.
|
|
@@ -951,6 +1076,27 @@ async function startDevServer(opts = {}) {
|
|
|
951
1076
|
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
952
1077
|
console.log(chalk.yellow(` Auto-generated projectId: ${config.projectId}`));
|
|
953
1078
|
}
|
|
1079
|
+
else if (!isValidProjectId(config.projectId)) {
|
|
1080
|
+
// A malformed projectId (hand-edited config) breaks the editor's republish
|
|
1081
|
+
// stability: published/local id prefixes stop matching and every publish
|
|
1082
|
+
// INSERTs duplicate design elements. Fail fast instead of corrupting data.
|
|
1083
|
+
console.error(chalk.red(`Error: invalid projectId "${config.projectId}" in ikas.config.json`));
|
|
1084
|
+
console.error(chalk.gray("projectId must be at least 6 alphanumeric characters (no '-' or '_'). " +
|
|
1085
|
+
"Restore the original generated value — do not hand-edit it."));
|
|
1086
|
+
process.exit(1);
|
|
1087
|
+
}
|
|
1088
|
+
// Component ids carry the same prefix/suffix contract as projectId; the dev
|
|
1089
|
+
// server syncs them into the editor (and from there into themes), so a
|
|
1090
|
+
// hand-edited id must be rejected before the server starts.
|
|
1091
|
+
const invalidComponents = findInvalidComponentIds(config.components, config.projectId);
|
|
1092
|
+
if (invalidComponents.length > 0) {
|
|
1093
|
+
console.error(chalk.red("Error: invalid component id(s) in ikas.config.json:"));
|
|
1094
|
+
invalidComponents.forEach((c) => {
|
|
1095
|
+
console.error(chalk.red(` - "${c.id}"${c.name ? ` (${c.name})` : ""} — ${c.reason}`));
|
|
1096
|
+
});
|
|
1097
|
+
console.error(chalk.gray(COMPONENT_ID_HINT));
|
|
1098
|
+
process.exit(1);
|
|
1099
|
+
}
|
|
954
1100
|
console.log(chalk.cyan("\n ikas Component Dev Server\n"));
|
|
955
1101
|
console.log(chalk.gray(` Project: ${config.name}`));
|
|
956
1102
|
console.log(chalk.gray(` Components: ${config.components.length}\n`));
|
|
@@ -1003,6 +1149,16 @@ async function startDevServer(opts = {}) {
|
|
|
1003
1149
|
console.error(chalk.red(` Failed to start WebSocket server: ${error.message}`));
|
|
1004
1150
|
process.exit(1);
|
|
1005
1151
|
}
|
|
1152
|
+
console.log(chalk.green(` Dev server listening on 127.0.0.1:${DEV_SERVER_PORT}`));
|
|
1153
|
+
// Studio reaches this server only through the tunnel + websocket routing
|
|
1154
|
+
// that `ikas theme dev` registers; a directly-started server is invisible
|
|
1155
|
+
// to the editor. Hint only on a TTY — under `ikas theme dev` stdio is
|
|
1156
|
+
// piped and the wrapper already handles the connection.
|
|
1157
|
+
if (process.stdout.isTTY) {
|
|
1158
|
+
console.log(chalk.yellow("\n Note: ikas Studio cannot connect to this server directly."));
|
|
1159
|
+
console.log(chalk.yellow(" To develop with the editor, run `ikas theme dev` in this folder —"));
|
|
1160
|
+
console.log(chalk.yellow(" it starts this server, opens a tunnel and registers it with your store."));
|
|
1161
|
+
}
|
|
1006
1162
|
// Watch for file changes
|
|
1007
1163
|
const watchPaths = [
|
|
1008
1164
|
"src/**/*.tsx",
|
|
@@ -1055,7 +1211,38 @@ async function startDevServer(opts = {}) {
|
|
|
1055
1211
|
if (normalizedPath === configPath) {
|
|
1056
1212
|
console.log(chalk.yellow("\n Config changed, reloading..."));
|
|
1057
1213
|
try {
|
|
1058
|
-
|
|
1214
|
+
const reloaded = JSON.parse(fs.readFileSync(configPath, "utf-8"));
|
|
1215
|
+
// The startup guards validated projectId/component ids once; a hot-reload
|
|
1216
|
+
// must not smuggle a hand-edited value past them — a malformed id reaching
|
|
1217
|
+
// `generateComponentId` or chunk namespacing corrupts republish matching.
|
|
1218
|
+
// Keep the session's validated projectId if the key was removed; reject the
|
|
1219
|
+
// reload outright (previous config stays active) on invalid values.
|
|
1220
|
+
if (!reloaded.projectId) {
|
|
1221
|
+
reloaded.projectId = config.projectId;
|
|
1222
|
+
}
|
|
1223
|
+
else if (!isValidProjectId(reloaded.projectId)) {
|
|
1224
|
+
console.error(chalk.red(` Ignoring config reload: invalid projectId "${reloaded.projectId}". `) +
|
|
1225
|
+
chalk.gray("Restore the original generated value — previous config stays active."));
|
|
1226
|
+
return;
|
|
1227
|
+
}
|
|
1228
|
+
const reloadedInvalidComponents = findInvalidComponentIds(reloaded.components ?? [], reloaded.projectId);
|
|
1229
|
+
if (reloadedInvalidComponents.length > 0) {
|
|
1230
|
+
console.error(chalk.red(` Ignoring config reload: invalid component id(s): ${reloadedInvalidComponents
|
|
1231
|
+
.map((c) => `"${c.id}" (${c.reason})`)
|
|
1232
|
+
.join(", ")}. `) +
|
|
1233
|
+
chalk.gray("Restore the original generated values — previous config stays active."));
|
|
1234
|
+
return;
|
|
1235
|
+
}
|
|
1236
|
+
// Well-formed is not enough: an id that changes while the server runs is
|
|
1237
|
+
// broadcast as `component-deleted` for the old one, and the editor then
|
|
1238
|
+
// removes the imported component and its page placements from the theme.
|
|
1239
|
+
const identityChanges = findIdentityChanges(config, reloaded);
|
|
1240
|
+
if (identityChanges.length > 0) {
|
|
1241
|
+
console.error(chalk.red(` Ignoring config reload: generated ids were changed (${identityChanges.join(", ")}). `) +
|
|
1242
|
+
chalk.gray("Restore the original generated values — previous config stays active."));
|
|
1243
|
+
return;
|
|
1244
|
+
}
|
|
1245
|
+
config = reloaded;
|
|
1059
1246
|
cachedCustomTypes = config.customTypes || [];
|
|
1060
1247
|
writeGlobalTypesFile(config);
|
|
1061
1248
|
await compileAllComponentsForDev(config);
|