@highstate/cli 0.9.18 → 0.9.20
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/assets/tsconfig.base.json +7 -2
- package/dist/highstate.manifest.json +1 -1
- package/dist/{library-loader-ZABUULFB.js → library-loader-6TJTW2HX.js} +3 -3
- package/dist/library-loader-6TJTW2HX.js.map +1 -0
- package/dist/main.js +391 -170
- package/dist/main.js.map +1 -1
- package/package.json +5 -5
- package/src/commands/backend/identity.ts +1 -1
- package/src/commands/package/create.ts +35 -0
- package/src/commands/package/index.ts +4 -0
- package/src/commands/package/list.ts +41 -0
- package/src/commands/package/remove.ts +40 -0
- package/src/commands/package/update-references.ts +18 -0
- package/src/main.ts +10 -0
- package/src/shared/index.ts +1 -0
- package/src/shared/library-loader.ts +1 -1
- package/src/shared/schema-transformer.spec.ts +178 -35
- package/src/shared/schema-transformer.ts +250 -244
- package/src/shared/source-hash-calculator.ts +0 -1
- package/src/shared/workspace.ts +240 -0
- package/dist/library-loader-ZABUULFB.js.map +0 -1
package/dist/main.js
CHANGED
|
@@ -8,22 +8,23 @@ import { colorize } from 'consola/utils';
|
|
|
8
8
|
import { getPort } from 'get-port-please';
|
|
9
9
|
import { PassThrough } from 'node:stream';
|
|
10
10
|
import pino, { levels } from 'pino';
|
|
11
|
-
import { writeFile, readFile } from 'node:fs/promises';
|
|
11
|
+
import { writeFile, rm, readFile, mkdir, readdir } from 'node:fs/promises';
|
|
12
12
|
import { parseAsync } from 'oxc-parser';
|
|
13
13
|
import { walk } from 'oxc-walker';
|
|
14
14
|
import MagicString from 'magic-string';
|
|
15
|
-
import { resolve, dirname, relative } from 'node:path';
|
|
15
|
+
import { resolve, dirname, relative, join } from 'node:path';
|
|
16
16
|
import { pathToFileURL, fileURLToPath } from 'node:url';
|
|
17
17
|
import { crc32 } from '@aws-crypto/crc32';
|
|
18
18
|
import { resolve as resolve$1 } from 'import-meta-resolve';
|
|
19
19
|
import { z } from 'zod';
|
|
20
|
+
import { existsSync } from 'node:fs';
|
|
20
21
|
import { pipe, mapValues, mapKeys } from 'remeda';
|
|
21
22
|
import { build } from 'tsup';
|
|
22
23
|
import { encode } from '@msgpack/msgpack';
|
|
23
24
|
import { identityToRecipient } from 'age-encryption';
|
|
24
25
|
|
|
25
26
|
// package.json
|
|
26
|
-
var version = "0.9.
|
|
27
|
+
var version = "0.9.19";
|
|
27
28
|
var logger = pino(
|
|
28
29
|
{
|
|
29
30
|
name: "highstate-cli",
|
|
@@ -93,192 +94,164 @@ var schemaTransformerPlugin = {
|
|
|
93
94
|
}
|
|
94
95
|
};
|
|
95
96
|
async function applySchemaTransformations(content) {
|
|
97
|
+
let result = await applyZodMetaTransformations(content);
|
|
98
|
+
result = await applyHelperFunctionTransformations(result);
|
|
99
|
+
result = await applyDefineFunctionMetaTransformations(result);
|
|
100
|
+
return result;
|
|
101
|
+
}
|
|
102
|
+
async function applyZodMetaTransformations(content) {
|
|
96
103
|
const { program, comments } = await parseAsync("file.ts", content);
|
|
97
|
-
const transformations = [];
|
|
98
104
|
const parentStack = [];
|
|
105
|
+
let hasTransformations = false;
|
|
106
|
+
const result = new MagicString(content);
|
|
99
107
|
walk(program, {
|
|
100
108
|
enter(node) {
|
|
101
109
|
parentStack.push(node);
|
|
102
|
-
if (node
|
|
103
|
-
const
|
|
104
|
-
if (
|
|
105
|
-
const
|
|
106
|
-
const fieldName = node.key.name;
|
|
107
|
-
const
|
|
108
|
-
if (!
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
newValue: `${originalValue2}.meta({ title: __camelCaseToHumanReadable("${fieldName}"), description: \`${description2}\` })`,
|
|
113
|
-
type: "zod-meta"
|
|
114
|
-
});
|
|
110
|
+
if (isZodObjectProperty(node, parentStack)) {
|
|
111
|
+
const jsdoc = findLeadingComment(content, node, comments);
|
|
112
|
+
if (jsdoc) {
|
|
113
|
+
const description = cleanJsdoc(jsdoc.value);
|
|
114
|
+
const fieldName = "name" in node.key && typeof node.key.name === "string" ? node.key.name : "unknown";
|
|
115
|
+
const originalValue = content.substring(node.value.start, node.value.end);
|
|
116
|
+
if (!originalValue.includes(".meta(")) {
|
|
117
|
+
const newValue = `${originalValue}.meta({ title: __camelCaseToHumanReadable("${fieldName}"), description: \`${description}\` })`;
|
|
118
|
+
result.update(node.value.start, node.value.end, newValue);
|
|
119
|
+
hasTransformations = true;
|
|
115
120
|
}
|
|
116
121
|
}
|
|
117
|
-
return;
|
|
118
|
-
}
|
|
119
|
-
if (node.type !== "Property" || node.key.type !== "Identifier") {
|
|
120
|
-
return;
|
|
121
|
-
}
|
|
122
|
-
const parentKey = getParentObjectKey(parentStack) || getMarkerFunctionName(parentStack);
|
|
123
|
-
if (!parentKey || !["inputs", "outputs", "args", "secrets"].includes(parentKey)) {
|
|
124
|
-
return;
|
|
125
|
-
}
|
|
126
|
-
const jsdoc = comments.find((comment) => isLeadingComment(content, node, comment));
|
|
127
|
-
if (!jsdoc) {
|
|
128
|
-
return;
|
|
129
|
-
}
|
|
130
|
-
const description = cleanJsdoc(jsdoc.value);
|
|
131
|
-
const originalValue = content.substring(node.value.start, node.value.end);
|
|
132
|
-
const entityField = ["inputs", "outputs"].includes(parentKey) ? "entity" : "schema";
|
|
133
|
-
const isAlreadyStructured = isStructuredValue(originalValue, entityField);
|
|
134
|
-
if (isAlreadyStructured) {
|
|
135
|
-
const modifiedValue = injectDescriptionIntoObject(originalValue, description);
|
|
136
|
-
transformations.push({
|
|
137
|
-
start: node.value.start,
|
|
138
|
-
end: node.value.end,
|
|
139
|
-
newValue: modifiedValue,
|
|
140
|
-
type: "schema-structure"
|
|
141
|
-
});
|
|
142
|
-
} else {
|
|
143
|
-
transformations.push({
|
|
144
|
-
start: node.value.start,
|
|
145
|
-
end: node.value.end,
|
|
146
|
-
newValue: `{
|
|
147
|
-
${entityField}: ${originalValue},
|
|
148
|
-
meta: {
|
|
149
|
-
description: \`${description}\`,
|
|
150
|
-
},
|
|
151
|
-
}`,
|
|
152
|
-
type: "schema-structure"
|
|
153
|
-
});
|
|
154
122
|
}
|
|
155
123
|
},
|
|
156
124
|
leave() {
|
|
157
125
|
parentStack.pop();
|
|
158
126
|
}
|
|
159
127
|
});
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
newValue
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
description: \`${description}\`,
|
|
196
|
-
},
|
|
197
|
-
}`,
|
|
198
|
-
containsZodMeta: true
|
|
199
|
-
};
|
|
128
|
+
let finalResult = result.toString();
|
|
129
|
+
if (hasTransformations && !content.includes("__camelCaseToHumanReadable")) {
|
|
130
|
+
finalResult = 'import { camelCaseToHumanReadable as __camelCaseToHumanReadable } from "@highstate/contract"\n' + finalResult;
|
|
131
|
+
}
|
|
132
|
+
return finalResult;
|
|
133
|
+
}
|
|
134
|
+
async function applyHelperFunctionTransformations(content) {
|
|
135
|
+
const { program, comments } = await parseAsync("file.ts", content);
|
|
136
|
+
const parentStack = [];
|
|
137
|
+
let hasTransformations = false;
|
|
138
|
+
const result = new MagicString(content);
|
|
139
|
+
walk(program, {
|
|
140
|
+
enter(node) {
|
|
141
|
+
parentStack.push(node);
|
|
142
|
+
if (node.type === "Property" && "key" in node && node.key?.type === "Identifier") {
|
|
143
|
+
const propertyNode = node;
|
|
144
|
+
const parentKey = getParentObjectKey(parentStack);
|
|
145
|
+
if (parentKey && ["inputs", "outputs", "args", "secrets"].includes(parentKey)) {
|
|
146
|
+
const jsdoc = findLeadingComment(content, node, comments);
|
|
147
|
+
if (jsdoc) {
|
|
148
|
+
const description = cleanJsdoc(jsdoc.value);
|
|
149
|
+
const originalValue = content.substring(
|
|
150
|
+
propertyNode.value.start,
|
|
151
|
+
propertyNode.value.end
|
|
152
|
+
);
|
|
153
|
+
let helperFunction;
|
|
154
|
+
if (["args", "secrets"].includes(parentKey)) {
|
|
155
|
+
helperFunction = "$addArgumentDescription";
|
|
156
|
+
} else {
|
|
157
|
+
helperFunction = "$addInputDescription";
|
|
158
|
+
}
|
|
159
|
+
const newValue = `${helperFunction}(${originalValue}, \`${description}\`)`;
|
|
160
|
+
result.update(propertyNode.value.start, propertyNode.value.end, newValue);
|
|
161
|
+
hasTransformations = true;
|
|
162
|
+
}
|
|
200
163
|
}
|
|
201
164
|
}
|
|
165
|
+
},
|
|
166
|
+
leave() {
|
|
167
|
+
parentStack.pop();
|
|
202
168
|
}
|
|
203
|
-
return { ...schemaTransform, containsZodMeta: false };
|
|
204
|
-
});
|
|
205
|
-
const independentZodMetas = zodMetaTransformations.filter((zodTransform) => {
|
|
206
|
-
return !schemaTransformations.some((schemaTransform) => {
|
|
207
|
-
return schemaTransform.start <= zodTransform.start && schemaTransform.end >= zodTransform.end;
|
|
208
|
-
});
|
|
209
|
-
});
|
|
210
|
-
const finalTransformations = [
|
|
211
|
-
...independentZodMetas,
|
|
212
|
-
...processedSchemaTransformations.map(({ containsZodMeta, ...rest }) => rest)
|
|
213
|
-
// eslint-disable-line @typescript-eslint/no-unused-vars
|
|
214
|
-
];
|
|
215
|
-
const hasZodMetaTransformations = zodMetaTransformations.length > 0;
|
|
216
|
-
const needsImport = hasZodMetaTransformations && !content.includes("__camelCaseToHumanReadable");
|
|
217
|
-
let result = content;
|
|
218
|
-
const magicString = new MagicString(result);
|
|
219
|
-
finalTransformations.sort((a, b) => b.start - a.start).forEach((transformation) => {
|
|
220
|
-
magicString.update(transformation.start, transformation.end, transformation.newValue);
|
|
221
169
|
});
|
|
222
|
-
|
|
223
|
-
if (
|
|
224
|
-
|
|
170
|
+
let finalResult = result.toString();
|
|
171
|
+
if (hasTransformations && !content.includes("$addArgumentDescription")) {
|
|
172
|
+
finalResult = 'import { $addArgumentDescription, $addInputDescription } from "@highstate/contract"\n' + finalResult;
|
|
225
173
|
}
|
|
226
|
-
return
|
|
174
|
+
return finalResult;
|
|
227
175
|
}
|
|
228
|
-
function
|
|
229
|
-
const
|
|
230
|
-
const
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
176
|
+
async function applyDefineFunctionMetaTransformations(content) {
|
|
177
|
+
const { program, comments } = await parseAsync("file.ts", content);
|
|
178
|
+
const parentStack = [];
|
|
179
|
+
const result = new MagicString(content);
|
|
180
|
+
walk(program, {
|
|
181
|
+
enter(node) {
|
|
182
|
+
parentStack.push(node);
|
|
183
|
+
if (node.type === "CallExpression" && "callee" in node && node.callee.type === "Identifier") {
|
|
184
|
+
const callNode = node;
|
|
185
|
+
const callee = callNode.callee;
|
|
186
|
+
const functionName = "name" in callee && typeof callee.name === "string" ? callee.name : void 0;
|
|
187
|
+
if (functionName && ["defineUnit", "defineEntity", "defineComponent"].includes(functionName)) {
|
|
188
|
+
const jsdoc = findJsdocForDefineFunction(content, parentStack, comments);
|
|
189
|
+
if (jsdoc && callNode.arguments && callNode.arguments.length > 0) {
|
|
190
|
+
const description = cleanJsdoc(jsdoc.value);
|
|
191
|
+
const firstArg = callNode.arguments[0];
|
|
192
|
+
if (firstArg.type === "ObjectExpression" && "properties" in firstArg) {
|
|
193
|
+
const properties = firstArg.properties;
|
|
194
|
+
const metaProperty = properties?.find(
|
|
195
|
+
(prop) => prop.type === "Property" && "key" in prop && prop.key?.type === "Identifier" && prop.key?.name === "meta"
|
|
196
|
+
);
|
|
197
|
+
if (metaProperty && "value" in metaProperty) {
|
|
198
|
+
const originalMetaValue = content.substring(
|
|
199
|
+
metaProperty.value.start,
|
|
200
|
+
metaProperty.value.end
|
|
201
|
+
);
|
|
202
|
+
const newMetaValue = injectDescriptionIntoMetaObject(originalMetaValue, description);
|
|
203
|
+
result.update(metaProperty.value.start, metaProperty.value.end, newMetaValue);
|
|
204
|
+
} else if (properties && properties.length > 0) {
|
|
205
|
+
const lastProperty = properties[properties.length - 1];
|
|
206
|
+
if (lastProperty && "end" in lastProperty) {
|
|
207
|
+
const insertPos = lastProperty.end;
|
|
208
|
+
const newMetaProperty = `,
|
|
209
|
+
|
|
252
210
|
meta: {
|
|
253
211
|
description: \`${description}\`,
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
212
|
+
}`;
|
|
213
|
+
result.appendLeft(insertPos, newMetaProperty);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
},
|
|
221
|
+
leave() {
|
|
222
|
+
parentStack.pop();
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
return result.toString();
|
|
265
226
|
}
|
|
266
|
-
function
|
|
227
|
+
function findJsdocForDefineFunction(content, parentStack, comments) {
|
|
267
228
|
for (let i = parentStack.length - 1; i >= 0; i--) {
|
|
268
229
|
const node = parentStack[i];
|
|
269
|
-
if (node.type === "
|
|
270
|
-
const
|
|
271
|
-
if (
|
|
272
|
-
|
|
273
|
-
|
|
230
|
+
if (node.type === "VariableDeclarator" && "id" in node && node.id?.type === "Identifier") {
|
|
231
|
+
const jsdoc = findLeadingComment(content, node, comments);
|
|
232
|
+
if (jsdoc) return jsdoc;
|
|
233
|
+
}
|
|
234
|
+
if (node.type === "VariableDeclaration") {
|
|
235
|
+
const jsdoc = findLeadingComment(content, node, comments);
|
|
236
|
+
if (jsdoc) return jsdoc;
|
|
237
|
+
}
|
|
238
|
+
if (node.type === "ExportNamedDeclaration" && "declaration" in node && node.declaration) {
|
|
239
|
+
const jsdoc = findLeadingComment(content, node, comments);
|
|
240
|
+
if (jsdoc) return jsdoc;
|
|
274
241
|
}
|
|
275
242
|
}
|
|
276
243
|
return null;
|
|
277
244
|
}
|
|
245
|
+
function isZodObjectProperty(node, parentStack) {
|
|
246
|
+
return node.type === "Property" && "key" in node && node.key?.type === "Identifier" && isInsideZodObject(parentStack);
|
|
247
|
+
}
|
|
248
|
+
function findLeadingComment(content, node, comments) {
|
|
249
|
+
return comments.find((comment) => isLeadingComment(content, node, comment)) ?? null;
|
|
250
|
+
}
|
|
278
251
|
function getParentObjectKey(parentStack) {
|
|
279
252
|
for (let i = parentStack.length - 2; i >= 0; i--) {
|
|
280
253
|
const node = parentStack[i];
|
|
281
|
-
if (node.type === "Property" && node.key.type === "Identifier") {
|
|
254
|
+
if (node.type === "Property" && "key" in node && node.key.type === "Identifier") {
|
|
282
255
|
return node.key.name;
|
|
283
256
|
}
|
|
284
257
|
}
|
|
@@ -294,24 +267,41 @@ function isLeadingComment(content, node, comment) {
|
|
|
294
267
|
function cleanJsdoc(str) {
|
|
295
268
|
return str.replace(/^\s*\*/gm, "").replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\${/g, "\\${").trim();
|
|
296
269
|
}
|
|
270
|
+
function injectDescriptionIntoMetaObject(objectString, description) {
|
|
271
|
+
const trimmed = objectString.trim();
|
|
272
|
+
const hasDescription = /description\s*:/.test(trimmed);
|
|
273
|
+
if (hasDescription) {
|
|
274
|
+
return trimmed.replace(/description\s*:\s*`[^`]*`/, `description: \`${description}\``);
|
|
275
|
+
} else {
|
|
276
|
+
const openBraceIndex = trimmed.indexOf("{");
|
|
277
|
+
if (openBraceIndex === -1) {
|
|
278
|
+
return trimmed;
|
|
279
|
+
}
|
|
280
|
+
const beforeBrace = trimmed.substring(0, openBraceIndex + 1);
|
|
281
|
+
const afterBrace = trimmed.substring(openBraceIndex + 1);
|
|
282
|
+
return `${beforeBrace}
|
|
283
|
+
description: \`${description}\`,${afterBrace}`;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
297
286
|
function isInsideZodObject(parentStack) {
|
|
298
287
|
for (let i = parentStack.length - 1; i >= 0; i--) {
|
|
299
288
|
const node = parentStack[i];
|
|
300
|
-
if (node.type === "CallExpression" && node.callee.type === "MemberExpression" && isZodObjectCall(node.callee)) {
|
|
289
|
+
if (node.type === "CallExpression" && "callee" in node && node.callee.type === "MemberExpression" && isZodObjectCall(node.callee)) {
|
|
301
290
|
return true;
|
|
302
291
|
}
|
|
303
292
|
}
|
|
304
293
|
return false;
|
|
305
294
|
}
|
|
306
295
|
function isZodObjectCall(memberExpression) {
|
|
307
|
-
if (memberExpression.type !== "MemberExpression") {
|
|
296
|
+
if (memberExpression.type !== "MemberExpression" || !("object" in memberExpression) || !("property" in memberExpression)) {
|
|
308
297
|
return false;
|
|
309
298
|
}
|
|
310
|
-
|
|
299
|
+
const member = memberExpression;
|
|
300
|
+
if (member.object.type === "Identifier" && "name" in member.object && member.object.name === "z" && member.property.type === "Identifier" && member.property.name === "object") {
|
|
311
301
|
return true;
|
|
312
302
|
}
|
|
313
|
-
if (
|
|
314
|
-
return startsWithZodCall(
|
|
303
|
+
if (member.property.type === "Identifier" && member.property.name === "object" && member.object.type === "CallExpression" && "callee" in member.object && member.object.callee.type === "MemberExpression") {
|
|
304
|
+
return startsWithZodCall(member.object);
|
|
315
305
|
}
|
|
316
306
|
return false;
|
|
317
307
|
}
|
|
@@ -320,11 +310,12 @@ function startsWithZodCall(callExpression) {
|
|
|
320
310
|
return false;
|
|
321
311
|
}
|
|
322
312
|
if (callExpression.callee.type === "MemberExpression") {
|
|
323
|
-
|
|
313
|
+
const callee = callExpression.callee;
|
|
314
|
+
if (callee.object.type === "Identifier" && "name" in callee.object && callee.object.name === "z") {
|
|
324
315
|
return true;
|
|
325
316
|
}
|
|
326
|
-
if (
|
|
327
|
-
return startsWithZodCall(
|
|
317
|
+
if (callee.object.type === "CallExpression") {
|
|
318
|
+
return startsWithZodCall(callee.object);
|
|
328
319
|
}
|
|
329
320
|
}
|
|
330
321
|
return false;
|
|
@@ -438,7 +429,6 @@ var SourceHashCalculator = class {
|
|
|
438
429
|
})
|
|
439
430
|
);
|
|
440
431
|
break;
|
|
441
|
-
case "auto":
|
|
442
432
|
default:
|
|
443
433
|
promises.push(
|
|
444
434
|
this.getFileHash(fullPath).then((hash) => ({
|
|
@@ -594,6 +584,151 @@ ${content}`,
|
|
|
594
584
|
}
|
|
595
585
|
};
|
|
596
586
|
}
|
|
587
|
+
var packageJsonSchema = z.object({
|
|
588
|
+
name: z.string(),
|
|
589
|
+
highstate: highstateConfigSchema.optional()
|
|
590
|
+
});
|
|
591
|
+
function generateTsconfigContent(workspaceRoot, packagePath) {
|
|
592
|
+
const relativePath = relative(workspaceRoot, packagePath);
|
|
593
|
+
const depth = relativePath.split("/").length;
|
|
594
|
+
const relativeNodeModules = `${"../".repeat(depth)}node_modules/@highstate/cli/assets/tsconfig.base.json`;
|
|
595
|
+
return {
|
|
596
|
+
extends: relativeNodeModules,
|
|
597
|
+
include: ["./src/**/*.ts", "./package.json", "./assets/**/*.json"]
|
|
598
|
+
};
|
|
599
|
+
}
|
|
600
|
+
async function findWorkspaceRoot(startPath = process.cwd()) {
|
|
601
|
+
let currentPath = resolve(startPath);
|
|
602
|
+
while (currentPath !== "/") {
|
|
603
|
+
const packageJsonPath = join(currentPath, "package.json");
|
|
604
|
+
if (existsSync(packageJsonPath)) {
|
|
605
|
+
try {
|
|
606
|
+
const content = await readFile(packageJsonPath, "utf-8");
|
|
607
|
+
const packageJson = JSON.parse(content);
|
|
608
|
+
if (packageJson.workspaces) {
|
|
609
|
+
return currentPath;
|
|
610
|
+
}
|
|
611
|
+
} catch {
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
const parentPath = resolve(currentPath, "..");
|
|
615
|
+
if (parentPath === currentPath) break;
|
|
616
|
+
currentPath = parentPath;
|
|
617
|
+
}
|
|
618
|
+
throw new Error("Could not find workspace root (no package.json with workspaces found)");
|
|
619
|
+
}
|
|
620
|
+
async function scanWorkspacePackages(workspaceRoot) {
|
|
621
|
+
const packages = [];
|
|
622
|
+
const packagesDir = join(workspaceRoot, "packages");
|
|
623
|
+
if (!existsSync(packagesDir)) {
|
|
624
|
+
return packages;
|
|
625
|
+
}
|
|
626
|
+
async function scanDirectory(dirPath, depth = 0) {
|
|
627
|
+
const dirName = relative(packagesDir, dirPath).split("/").pop();
|
|
628
|
+
if (dirName?.startsWith(".") || dirName === "node_modules") {
|
|
629
|
+
return;
|
|
630
|
+
}
|
|
631
|
+
const entries = await readdir(dirPath, { withFileTypes: true });
|
|
632
|
+
for (const entry of entries) {
|
|
633
|
+
if (!entry.isDirectory()) continue;
|
|
634
|
+
const entryPath = join(dirPath, entry.name);
|
|
635
|
+
if (entry.name.startsWith(".") || entry.name === "node_modules") {
|
|
636
|
+
continue;
|
|
637
|
+
}
|
|
638
|
+
const packageJsonPath = join(entryPath, "package.json");
|
|
639
|
+
if (existsSync(packageJsonPath)) {
|
|
640
|
+
try {
|
|
641
|
+
const content = await readFile(packageJsonPath, "utf-8");
|
|
642
|
+
const packageJson = packageJsonSchema.parse(JSON.parse(content));
|
|
643
|
+
const relativePath = relative(workspaceRoot, entryPath);
|
|
644
|
+
const type = packageJson.highstate?.type ?? "source";
|
|
645
|
+
packages.push({
|
|
646
|
+
path: entryPath,
|
|
647
|
+
relativePath,
|
|
648
|
+
name: packageJson.name,
|
|
649
|
+
type
|
|
650
|
+
});
|
|
651
|
+
} catch {
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
if (depth < 3) {
|
|
655
|
+
await scanDirectory(entryPath, depth + 1);
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
await scanDirectory(packagesDir);
|
|
660
|
+
return packages.sort((a, b) => a.relativePath.localeCompare(b.relativePath));
|
|
661
|
+
}
|
|
662
|
+
async function updateTsconfigReferences(workspaceRoot, packages, ensureTsconfigs = false) {
|
|
663
|
+
const tsconfigPath = join(workspaceRoot, "tsconfig.json");
|
|
664
|
+
if (ensureTsconfigs) {
|
|
665
|
+
await ensurePackageTsconfigs(
|
|
666
|
+
workspaceRoot,
|
|
667
|
+
// only udate for Highstate-managed packages
|
|
668
|
+
packages.filter((pkg) => pkg.type !== void 0)
|
|
669
|
+
);
|
|
670
|
+
}
|
|
671
|
+
const references = packages.map((pkg) => ({
|
|
672
|
+
path: `./${pkg.relativePath}/tsconfig.json`
|
|
673
|
+
}));
|
|
674
|
+
const tsconfigContent = {
|
|
675
|
+
files: [],
|
|
676
|
+
references
|
|
677
|
+
};
|
|
678
|
+
await writeFile(tsconfigPath, `${JSON.stringify(tsconfigContent, null, 2)}
|
|
679
|
+
`, "utf-8");
|
|
680
|
+
}
|
|
681
|
+
async function ensurePackageTsconfigs(workspaceRoot, packages) {
|
|
682
|
+
for (const pkg of packages) {
|
|
683
|
+
const tsconfigPath = join(pkg.path, "tsconfig.json");
|
|
684
|
+
const tsconfigContent = generateTsconfigContent(workspaceRoot, pkg.path);
|
|
685
|
+
await writeFile(tsconfigPath, `${JSON.stringify(tsconfigContent, null, 2)}
|
|
686
|
+
`, "utf-8");
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
async function createPackage(workspaceRoot, name, type) {
|
|
690
|
+
const packagePath = join(workspaceRoot, "packages", name);
|
|
691
|
+
const srcPath = join(packagePath, "src");
|
|
692
|
+
await mkdir(packagePath, { recursive: true });
|
|
693
|
+
await mkdir(srcPath, { recursive: true });
|
|
694
|
+
const packageJson = {
|
|
695
|
+
name: `@highstate/${name}`,
|
|
696
|
+
version: "0.0.1",
|
|
697
|
+
type: "module",
|
|
698
|
+
highstate: {
|
|
699
|
+
type
|
|
700
|
+
}
|
|
701
|
+
};
|
|
702
|
+
await writeFile(
|
|
703
|
+
join(packagePath, "package.json"),
|
|
704
|
+
`${JSON.stringify(packageJson, null, 2)}
|
|
705
|
+
`,
|
|
706
|
+
"utf-8"
|
|
707
|
+
);
|
|
708
|
+
const tsconfigContent = generateTsconfigContent(workspaceRoot, packagePath);
|
|
709
|
+
await writeFile(
|
|
710
|
+
join(packagePath, "tsconfig.json"),
|
|
711
|
+
`${JSON.stringify(tsconfigContent, null, 2)}
|
|
712
|
+
`,
|
|
713
|
+
"utf-8"
|
|
714
|
+
);
|
|
715
|
+
await writeFile(
|
|
716
|
+
join(packagePath, "CHANGELOG.md"),
|
|
717
|
+
`# Changelog
|
|
718
|
+
|
|
719
|
+
All notable changes to this project will be documented in this file.
|
|
720
|
+
`,
|
|
721
|
+
"utf-8"
|
|
722
|
+
);
|
|
723
|
+
await writeFile(join(srcPath, "index.ts"), `// ${name} package
|
|
724
|
+
`, "utf-8");
|
|
725
|
+
return {
|
|
726
|
+
path: packagePath,
|
|
727
|
+
relativePath: `packages/${name}`,
|
|
728
|
+
name: `@highstate/${name}`,
|
|
729
|
+
type
|
|
730
|
+
};
|
|
731
|
+
}
|
|
597
732
|
|
|
598
733
|
// src/commands/designer.ts
|
|
599
734
|
var DesignerCommand = class extends Command {
|
|
@@ -619,10 +754,10 @@ var DesignerCommand = class extends Command {
|
|
|
619
754
|
const port = await getPort();
|
|
620
755
|
process.env.NITRO_PORT = port.toString();
|
|
621
756
|
process.env.NITRO_HOST = "0.0.0.0";
|
|
622
|
-
await new Promise((
|
|
757
|
+
await new Promise((resolve4) => {
|
|
623
758
|
console.log = (message) => {
|
|
624
759
|
if (message.startsWith("Listening on")) {
|
|
625
|
-
|
|
760
|
+
resolve4();
|
|
626
761
|
}
|
|
627
762
|
};
|
|
628
763
|
const path = "@highstate/designer/.output/server/index.mjs";
|
|
@@ -759,7 +894,7 @@ var BuildCommand = class extends Command {
|
|
|
759
894
|
await sourceHashCalculator.writeHighstateManifest("./dist", distPathToExportKey);
|
|
760
895
|
}
|
|
761
896
|
if (this.library) {
|
|
762
|
-
const { loadLibrary } = await import('./library-loader-
|
|
897
|
+
const { loadLibrary } = await import('./library-loader-6TJTW2HX.js');
|
|
763
898
|
const fullModulePaths = Object.values(entry).map((value) => resolve(value.distPath));
|
|
764
899
|
logger.info("evaluating library components from modules: %s", fullModulePaths.join(", "));
|
|
765
900
|
const library = await loadLibrary(logger, fullModulePaths);
|
|
@@ -784,6 +919,88 @@ var BackendIdentityCommand = class extends Command {
|
|
|
784
919
|
logger.info(`run "highstate backend unlock-method add ${recipient}" on other authorized device`);
|
|
785
920
|
}
|
|
786
921
|
};
|
|
922
|
+
var UpdateReferencesCommand = class extends Command {
|
|
923
|
+
static paths = [["package", "update-references"]];
|
|
924
|
+
static usage = Command.Usage({
|
|
925
|
+
category: "Package",
|
|
926
|
+
description: "Updates the root tsconfig.json with references to all packages in the workspace."
|
|
927
|
+
});
|
|
928
|
+
async execute() {
|
|
929
|
+
const workspaceRoot = await findWorkspaceRoot();
|
|
930
|
+
const packages = await scanWorkspacePackages(workspaceRoot);
|
|
931
|
+
await updateTsconfigReferences(workspaceRoot, packages, true);
|
|
932
|
+
}
|
|
933
|
+
};
|
|
934
|
+
var ListCommand = class extends Command {
|
|
935
|
+
static paths = [["package", "list"]];
|
|
936
|
+
static usage = Command.Usage({
|
|
937
|
+
category: "Package",
|
|
938
|
+
description: "Lists all packages in the workspace with their types."
|
|
939
|
+
});
|
|
940
|
+
async execute() {
|
|
941
|
+
const workspaceRoot = await findWorkspaceRoot();
|
|
942
|
+
const packages = await scanWorkspacePackages(workspaceRoot);
|
|
943
|
+
if (packages.length === 0) {
|
|
944
|
+
console.log("No packages found in workspace.");
|
|
945
|
+
return;
|
|
946
|
+
}
|
|
947
|
+
const nameWidth = Math.max(4, ...packages.map((pkg) => pkg.name.length));
|
|
948
|
+
const typeWidth = Math.max(4, ...packages.map((pkg) => pkg.type?.length ?? 0));
|
|
949
|
+
const pathWidth = Math.max(4, ...packages.map((pkg) => pkg.relativePath.length));
|
|
950
|
+
console.log(
|
|
951
|
+
`${"Name".padEnd(nameWidth)} ${"Type".padEnd(typeWidth)} ${"Path".padEnd(pathWidth)}`
|
|
952
|
+
);
|
|
953
|
+
console.log(`${"-".repeat(nameWidth)} ${"-".repeat(typeWidth)} ${"-".repeat(pathWidth)}`);
|
|
954
|
+
for (const pkg of packages) {
|
|
955
|
+
const type = pkg.type ?? "unknown";
|
|
956
|
+
console.log(
|
|
957
|
+
`${pkg.name.padEnd(nameWidth)} ${type.padEnd(typeWidth)} ${pkg.relativePath.padEnd(pathWidth)}`
|
|
958
|
+
);
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
};
|
|
962
|
+
var CreateCommand = class extends Command {
|
|
963
|
+
static paths = [["package", "create"]];
|
|
964
|
+
static usage = Command.Usage({
|
|
965
|
+
category: "Package",
|
|
966
|
+
description: "Creates a new package in the workspace."
|
|
967
|
+
});
|
|
968
|
+
name = Option.String({ required: true });
|
|
969
|
+
type = Option.String("--type,-t", {
|
|
970
|
+
description: "Package type (source, library, worker)"
|
|
971
|
+
});
|
|
972
|
+
async execute() {
|
|
973
|
+
const workspaceRoot = await findWorkspaceRoot();
|
|
974
|
+
const packageType = highstateConfigSchema.shape.type.parse(this.type);
|
|
975
|
+
await createPackage(workspaceRoot, this.name, packageType);
|
|
976
|
+
const packages = await scanWorkspacePackages(workspaceRoot);
|
|
977
|
+
await updateTsconfigReferences(workspaceRoot, packages);
|
|
978
|
+
console.log(`Created package: @highstate/${this.name} (${packageType})`);
|
|
979
|
+
}
|
|
980
|
+
};
|
|
981
|
+
var RemoveCommand = class extends Command {
|
|
982
|
+
static paths = [["package", "remove"]];
|
|
983
|
+
static usage = Command.Usage({
|
|
984
|
+
category: "Package",
|
|
985
|
+
description: "Removes a package from the workspace."
|
|
986
|
+
});
|
|
987
|
+
name = Option.String({ required: true });
|
|
988
|
+
async execute() {
|
|
989
|
+
const workspaceRoot = await findWorkspaceRoot();
|
|
990
|
+
const packages = await scanWorkspacePackages(workspaceRoot);
|
|
991
|
+
const targetPackage = packages.find(
|
|
992
|
+
(pkg) => pkg.name === this.name || pkg.name === `@highstate/${this.name}` || pkg.relativePath.endsWith(this.name)
|
|
993
|
+
);
|
|
994
|
+
if (!targetPackage) {
|
|
995
|
+
console.error(`Package not found: ${this.name}`);
|
|
996
|
+
process.exit(1);
|
|
997
|
+
}
|
|
998
|
+
await rm(targetPackage.path, { recursive: true, force: true });
|
|
999
|
+
const remainingPackages = await scanWorkspacePackages(workspaceRoot);
|
|
1000
|
+
await updateTsconfigReferences(workspaceRoot, remainingPackages);
|
|
1001
|
+
console.log(`Removed package: ${targetPackage.name}`);
|
|
1002
|
+
}
|
|
1003
|
+
};
|
|
787
1004
|
|
|
788
1005
|
// src/main.ts
|
|
789
1006
|
var cli = new Cli({
|
|
@@ -794,6 +1011,10 @@ var cli = new Cli({
|
|
|
794
1011
|
cli.register(BuildCommand);
|
|
795
1012
|
cli.register(DesignerCommand);
|
|
796
1013
|
cli.register(BackendIdentityCommand);
|
|
1014
|
+
cli.register(UpdateReferencesCommand);
|
|
1015
|
+
cli.register(ListCommand);
|
|
1016
|
+
cli.register(CreateCommand);
|
|
1017
|
+
cli.register(RemoveCommand);
|
|
797
1018
|
cli.register(Builtins.HelpCommand);
|
|
798
1019
|
cli.register(Builtins.VersionCommand);
|
|
799
1020
|
await cli.runExit(process.argv.slice(2));
|