@atmyapp/cli 0.0.7 → 0.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,36 @@
1
+ export interface AmaSession {
2
+ token: string;
3
+ projectId: string;
4
+ url: string;
5
+ }
6
+ export interface SessionOverrides {
7
+ token?: string;
8
+ projectId?: string;
9
+ url?: string;
10
+ }
11
+ export type AmaFetch = ReturnType<typeof createAmaFetch>;
12
+ export interface SseEvent<T = unknown> {
13
+ event?: string;
14
+ id?: string;
15
+ retry?: number;
16
+ data: string;
17
+ parsed?: T;
18
+ raw: string;
19
+ }
20
+ export interface StreamSseOptions<T = unknown> {
21
+ url: string;
22
+ fetchInit?: RequestInit;
23
+ signal?: AbortSignal;
24
+ onEvent: (event: SseEvent<T>) => void | Promise<void>;
25
+ }
26
+ export declare function resolveSession(overrides?: SessionOverrides): AmaSession;
27
+ export declare function createAmaFetch(session: AmaSession): import("@better-fetch/fetch").BetterFetch<{
28
+ baseURL: string;
29
+ headers: {
30
+ Authorization: string;
31
+ };
32
+ throw: false;
33
+ }, unknown, unknown, unknown>;
34
+ export declare function projectUrl(session: AmaSession, subPath: string, query?: Record<string, string | number | boolean | null | undefined>): string;
35
+ export declare function streamSse<T = unknown>(options: StreamSseOptions<T>): Promise<void>;
36
+ export declare function encodePathSegment(path: string): string;
@@ -0,0 +1,242 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __rest = (this && this.__rest) || function (s, e) {
12
+ var t = {};
13
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
14
+ t[p] = s[p];
15
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
16
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
17
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
18
+ t[p[i]] = s[p[i]];
19
+ }
20
+ return t;
21
+ };
22
+ Object.defineProperty(exports, "__esModule", { value: true });
23
+ exports.resolveSession = resolveSession;
24
+ exports.createAmaFetch = createAmaFetch;
25
+ exports.projectUrl = projectUrl;
26
+ exports.streamSse = streamSse;
27
+ exports.encodePathSegment = encodePathSegment;
28
+ const fetch_1 = require("@better-fetch/fetch");
29
+ const config_1 = require("./config");
30
+ function resolveSession(overrides = {}) {
31
+ var _a, _b, _c;
32
+ let config;
33
+ try {
34
+ config = (0, config_1.getConfig)();
35
+ }
36
+ catch (error) {
37
+ throw new Error("AMA session not configured. Run 'ama use' first or supply --url, --token, and --project-id options.");
38
+ }
39
+ const token = (_a = overrides.token) !== null && _a !== void 0 ? _a : config.token;
40
+ const projectId = (_b = overrides.projectId) !== null && _b !== void 0 ? _b : config.projectId;
41
+ const url = (_c = overrides.url) !== null && _c !== void 0 ? _c : config.url;
42
+ if (!token) {
43
+ throw new Error("Authentication token is missing. Run 'ama use' or provide it with --token.");
44
+ }
45
+ if (!url) {
46
+ throw new Error("Project URL is missing. Run 'ama use' or provide it with --url.");
47
+ }
48
+ if (!projectId) {
49
+ throw new Error("Project ID is missing. Ensure the URL contains /projects/{id} or pass --project-id.");
50
+ }
51
+ return {
52
+ token,
53
+ projectId,
54
+ url: stripTrailingSlashes(url),
55
+ };
56
+ }
57
+ function createAmaFetch(session) {
58
+ return (0, fetch_1.createFetch)({
59
+ baseURL: ensureTrailingSlash(session.url),
60
+ headers: {
61
+ Authorization: `Bearer ${session.token}`,
62
+ },
63
+ throw: false,
64
+ });
65
+ }
66
+ function projectUrl(session, subPath, query) {
67
+ const base = ensureTrailingSlash(session.url);
68
+ const cleanPath = subPath.replace(/^\/+/, "");
69
+ const url = new URL(cleanPath, base);
70
+ if (query) {
71
+ const params = new URLSearchParams();
72
+ for (const [key, value] of Object.entries(query)) {
73
+ if (value === undefined || value === null) {
74
+ continue;
75
+ }
76
+ params.append(key, typeof value === "boolean" ? String(value) : String(value));
77
+ }
78
+ const queryString = params.toString();
79
+ if (queryString) {
80
+ url.search = queryString;
81
+ }
82
+ }
83
+ return url.toString();
84
+ }
85
+ function streamSse(options) {
86
+ return __awaiter(this, void 0, void 0, function* () {
87
+ var _a;
88
+ const { url, onEvent, signal, fetchInit = {} } = options;
89
+ const { signal: initSignal, headers: initHeaders } = fetchInit, restInit = __rest(fetchInit, ["signal", "headers"]);
90
+ const headers = new Headers(initHeaders !== null && initHeaders !== void 0 ? initHeaders : {});
91
+ if (!headers.has("Accept")) {
92
+ headers.set("Accept", "text/event-stream");
93
+ }
94
+ const requestInit = Object.assign(Object.assign({ method: (_a = restInit.method) !== null && _a !== void 0 ? _a : "GET" }, restInit), { headers, signal: signal !== null && signal !== void 0 ? signal : initSignal });
95
+ const response = yield fetch(url, requestInit);
96
+ if (!response.ok) {
97
+ const errorBody = yield safeReadText(response);
98
+ throw new Error(`Request failed with status ${response.status}: ${errorBody !== null && errorBody !== void 0 ? errorBody : "<no body>"}`);
99
+ }
100
+ if (!response.body) {
101
+ throw new Error("Streaming response body is not available.");
102
+ }
103
+ const reader = response.body.getReader();
104
+ const decoder = new TextDecoder("utf-8");
105
+ let buffer = "";
106
+ while (true) {
107
+ const { done, value } = yield reader.read();
108
+ if (done) {
109
+ break;
110
+ }
111
+ buffer += decoder.decode(value, { stream: true });
112
+ buffer = yield dispatchSseBuffer(buffer, onEvent);
113
+ }
114
+ buffer += decoder.decode();
115
+ yield dispatchSseBuffer(buffer, onEvent, true);
116
+ });
117
+ }
118
+ function encodePathSegment(path) {
119
+ return path
120
+ .split("/")
121
+ .map((segment) => segment === "" || segment === "." ? segment : encodeURIComponent(segment))
122
+ .join("/");
123
+ }
124
+ function stripTrailingSlashes(value) {
125
+ return value.replace(/\/+$/, "");
126
+ }
127
+ function ensureTrailingSlash(value) {
128
+ return value.endsWith("/") ? value : `${value}/`;
129
+ }
130
+ function dispatchSseBuffer(buffer_1, onEvent_1) {
131
+ return __awaiter(this, arguments, void 0, function* (buffer, onEvent, flush = false) {
132
+ let working = buffer;
133
+ while (true) {
134
+ const delimiter = nextDelimiter(working);
135
+ if (!delimiter) {
136
+ break;
137
+ }
138
+ const { index, length } = delimiter;
139
+ const rawEvent = working.slice(0, index);
140
+ working = working.slice(index + length);
141
+ if (!rawEvent.trim()) {
142
+ continue;
143
+ }
144
+ const event = parseSseEvent(rawEvent);
145
+ if (event) {
146
+ yield onEvent(event);
147
+ }
148
+ }
149
+ if (flush && working.trim()) {
150
+ const event = parseSseEvent(working);
151
+ if (event) {
152
+ yield onEvent(event);
153
+ }
154
+ return "";
155
+ }
156
+ return working;
157
+ });
158
+ }
159
+ function nextDelimiter(buffer) {
160
+ const lfIndex = buffer.indexOf("\n\n");
161
+ const crlfIndex = buffer.indexOf("\r\n\r\n");
162
+ if (lfIndex === -1 && crlfIndex === -1) {
163
+ return null;
164
+ }
165
+ if (lfIndex === -1) {
166
+ return { index: crlfIndex, length: 4 };
167
+ }
168
+ if (crlfIndex === -1) {
169
+ return { index: lfIndex, length: 2 };
170
+ }
171
+ return lfIndex < crlfIndex
172
+ ? { index: lfIndex, length: 2 }
173
+ : { index: crlfIndex, length: 4 };
174
+ }
175
+ function parseSseEvent(raw) {
176
+ const trimmed = raw.trim();
177
+ if (!trimmed) {
178
+ return null;
179
+ }
180
+ const lines = trimmed.split(/\r?\n/);
181
+ const dataLines = [];
182
+ const event = {
183
+ data: "",
184
+ raw: trimmed,
185
+ };
186
+ for (const line of lines) {
187
+ if (!line) {
188
+ continue;
189
+ }
190
+ if (line.startsWith(":")) {
191
+ continue;
192
+ }
193
+ const separatorIndex = line.indexOf(":");
194
+ const field = separatorIndex === -1 ? line : line.slice(0, separatorIndex).trim();
195
+ const value = separatorIndex === -1
196
+ ? ""
197
+ : line
198
+ .slice(separatorIndex + 1)
199
+ .replace(/^\s+/, "");
200
+ switch (field) {
201
+ case "event":
202
+ event.event = value;
203
+ break;
204
+ case "data":
205
+ dataLines.push(value);
206
+ break;
207
+ case "id":
208
+ event.id = value;
209
+ break;
210
+ case "retry":
211
+ {
212
+ const numeric = Number(value);
213
+ if (!Number.isNaN(numeric)) {
214
+ event.retry = numeric;
215
+ }
216
+ }
217
+ break;
218
+ default:
219
+ break;
220
+ }
221
+ }
222
+ event.data = dataLines.join("\n");
223
+ if (event.data) {
224
+ try {
225
+ event.parsed = JSON.parse(event.data);
226
+ }
227
+ catch (error) {
228
+ // Non-JSON payloads are expected occasionally (e.g. [DONE])
229
+ }
230
+ }
231
+ return event;
232
+ }
233
+ function safeReadText(response) {
234
+ return __awaiter(this, void 0, void 0, function* () {
235
+ try {
236
+ return yield response.text();
237
+ }
238
+ catch (error) {
239
+ return null;
240
+ }
241
+ });
242
+ }
@@ -93,6 +93,13 @@ function processFilesParallel(files, tsconfigPath, continueOnError, logger, maxW
93
93
  logger.error("Parallel processing failed:", error);
94
94
  throw error;
95
95
  }
96
+ const { createProject, extractMdxConfigsFromSourceFiles } = require("./schema-processor");
97
+ const project = createProject(relevantFiles, tsconfigPath, logger);
98
+ const mdxConfigs = extractMdxConfigsFromSourceFiles(project.getSourceFiles(), logger);
99
+ if (mdxConfigs.length > 0) {
100
+ contents.push(...mdxConfigs);
101
+ successCount += mdxConfigs.length;
102
+ }
96
103
  return { contents, errors, successCount, failureCount };
97
104
  });
98
105
  }
@@ -114,7 +121,8 @@ function filterRelevantFiles(files, logger) {
114
121
  // Quick text search for ATMYAPP export
115
122
  const content = yield fs.readFile(file, "utf8");
116
123
  // Simple regex to check for ATMYAPP exports
117
- if (/export\s+type\s+ATMYAPP\s*=/.test(content)) {
124
+ if (/export\s+type\s+ATMYAPP\s*=/.test(content) ||
125
+ /AmaMdxConfigDef/.test(content)) {
118
126
  return file;
119
127
  }
120
128
  return null;
@@ -3,5 +3,6 @@ import { Logger } from "../logger";
3
3
  import { Content, ProcessingResult } from "../types/migrate";
4
4
  export declare function scanFiles(patterns: string[], logger: Logger): Promise<string[]>;
5
5
  export declare function createProject(files: string[], tsconfigPath: string, logger: Logger): Project;
6
+ export declare function extractMdxConfigsFromSourceFiles(sourceFiles: SourceFile[], logger: Logger): Content[];
6
7
  export declare function processAtmyappExport(atmyappType: TypeAliasDeclaration, file: SourceFile, tsconfigPath: string, logger: Logger): Content[];
7
8
  export declare function processFiles(sourceFiles: SourceFile[], tsconfigPath: string, continueOnError: boolean, logger: Logger): ProcessingResult;
@@ -47,6 +47,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
47
47
  Object.defineProperty(exports, "__esModule", { value: true });
48
48
  exports.scanFiles = scanFiles;
49
49
  exports.createProject = createProject;
50
+ exports.extractMdxConfigsFromSourceFiles = extractMdxConfigsFromSourceFiles;
50
51
  exports.processAtmyappExport = processAtmyappExport;
51
52
  exports.processFiles = processFiles;
52
53
  const fast_glob_1 = __importDefault(require("fast-glob"));
@@ -202,6 +203,209 @@ function extractEventInfoFromAST(file, definitionType, logger) {
202
203
  return null;
203
204
  }
204
205
  }
206
+ function getTypeAliasByName(file, name) {
207
+ const project = file.getProject();
208
+ for (const sourceFile of project.getSourceFiles()) {
209
+ const alias = sourceFile.getTypeAlias(name);
210
+ if (alias) {
211
+ return alias;
212
+ }
213
+ }
214
+ return undefined;
215
+ }
216
+ function extractStringLiteral(typeNode) {
217
+ if (!ts_morph_1.Node.isLiteralTypeNode(typeNode)) {
218
+ return null;
219
+ }
220
+ const literal = typeNode.getLiteral();
221
+ return ts_morph_1.Node.isStringLiteral(literal) ? literal.getLiteralValue() : null;
222
+ }
223
+ function mapPrimitiveType(typeNode) {
224
+ switch (typeNode.getKind()) {
225
+ case ts.SyntaxKind.StringKeyword:
226
+ return "string";
227
+ case ts.SyntaxKind.NumberKeyword:
228
+ return "number";
229
+ case ts.SyntaxKind.BooleanKeyword:
230
+ return "boolean";
231
+ case ts.SyntaxKind.ObjectKeyword:
232
+ return "object";
233
+ default:
234
+ break;
235
+ }
236
+ if (ts_morph_1.Node.isLiteralTypeNode(typeNode)) {
237
+ const literal = typeNode.getLiteral();
238
+ if (ts_morph_1.Node.isStringLiteral(literal)) {
239
+ return "string";
240
+ }
241
+ if (ts_morph_1.Node.isNumericLiteral(literal)) {
242
+ return "number";
243
+ }
244
+ if (literal.getKind() === ts.SyntaxKind.TrueKeyword || literal.getKind() === ts.SyntaxKind.FalseKeyword) {
245
+ return "boolean";
246
+ }
247
+ }
248
+ return null;
249
+ }
250
+ function mapPropType(typeNode, file) {
251
+ var _a;
252
+ if (ts_morph_1.Node.isUnionTypeNode(typeNode)) {
253
+ const nonNullable = typeNode
254
+ .getTypeNodes()
255
+ .filter((node) => node.getKind() !== ts.SyntaxKind.UndefinedKeyword &&
256
+ node.getKind() !== ts.SyntaxKind.NullKeyword);
257
+ if (nonNullable.length === 1) {
258
+ return mapPropType(nonNullable[0], file);
259
+ }
260
+ return "object";
261
+ }
262
+ if (ts_morph_1.Node.isArrayTypeNode(typeNode)) {
263
+ const elementType = mapPrimitiveType(typeNode.getElementTypeNode());
264
+ return elementType ? `${elementType}[]` : "object";
265
+ }
266
+ if (ts_morph_1.Node.isTypeReference(typeNode)) {
267
+ const typeName = typeNode.getTypeName();
268
+ if (ts_morph_1.Node.isIdentifier(typeName) && typeName.getText() === "Array") {
269
+ const args = typeNode.getTypeArguments();
270
+ if (args.length > 0) {
271
+ const elementType = mapPrimitiveType(args[0]);
272
+ return elementType ? `${elementType}[]` : "object";
273
+ }
274
+ }
275
+ return "object";
276
+ }
277
+ if (ts_morph_1.Node.isTypeLiteral(typeNode)) {
278
+ return "object";
279
+ }
280
+ return (_a = mapPrimitiveType(typeNode)) !== null && _a !== void 0 ? _a : "object";
281
+ }
282
+ function extractPropsFromTypeNode(typeNode, file) {
283
+ if (!typeNode) {
284
+ return undefined;
285
+ }
286
+ if (ts_morph_1.Node.isTypeReference(typeNode)) {
287
+ const typeName = typeNode.getTypeName();
288
+ if (ts_morph_1.Node.isIdentifier(typeName)) {
289
+ const alias = getTypeAliasByName(file, typeName.getText());
290
+ if (alias) {
291
+ return extractPropsFromTypeNode(alias.getTypeNode(), file);
292
+ }
293
+ }
294
+ }
295
+ if (!ts_morph_1.Node.isTypeLiteral(typeNode)) {
296
+ return undefined;
297
+ }
298
+ const props = {};
299
+ typeNode.getMembers().forEach((member) => {
300
+ if (!ts_morph_1.Node.isPropertySignature(member)) {
301
+ return;
302
+ }
303
+ const name = member.getName();
304
+ const propTypeNode = member.getTypeNode();
305
+ if (!propTypeNode || typeof name !== "string" || name.length === 0) {
306
+ return;
307
+ }
308
+ props[name] = mapPropType(propTypeNode, file);
309
+ });
310
+ return Object.keys(props).length > 0 ? props : undefined;
311
+ }
312
+ function extractComponentFromTypeNode(typeNode, file, logger) {
313
+ if (!ts_morph_1.Node.isTypeReference(typeNode)) {
314
+ return null;
315
+ }
316
+ const typeName = typeNode.getTypeName();
317
+ if (!ts_morph_1.Node.isIdentifier(typeName)) {
318
+ return null;
319
+ }
320
+ const typeNameText = typeName.getText();
321
+ if (typeNameText !== "AmaComponentDef") {
322
+ const alias = getTypeAliasByName(file, typeNameText);
323
+ if (!alias) {
324
+ return null;
325
+ }
326
+ const aliasTypeNode = alias.getTypeNode();
327
+ if (!aliasTypeNode) {
328
+ return null;
329
+ }
330
+ return extractComponentFromTypeNode(aliasTypeNode, file, logger);
331
+ }
332
+ const typeArguments = typeNode.getTypeArguments();
333
+ if (typeArguments.length === 0) {
334
+ return null;
335
+ }
336
+ const componentName = extractStringLiteral(typeArguments[0]);
337
+ if (!componentName) {
338
+ logger.warn(`MDX component name is not a string literal in ${file.getFilePath()}`);
339
+ return null;
340
+ }
341
+ const props = extractPropsFromTypeNode(typeArguments[1], file);
342
+ return Object.assign({ name: componentName }, (props ? { props } : {}));
343
+ }
344
+ function extractMdxConfigsFromAST(file, logger) {
345
+ const configs = {};
346
+ file.getTypeAliases().forEach((alias) => {
347
+ const typeNode = alias.getTypeNode();
348
+ if (!typeNode || !ts_morph_1.Node.isTypeReference(typeNode)) {
349
+ return;
350
+ }
351
+ const typeName = typeNode.getTypeName();
352
+ if (!ts_morph_1.Node.isIdentifier(typeName) || typeName.getText() !== "AmaMdxConfigDef") {
353
+ return;
354
+ }
355
+ const typeArguments = typeNode.getTypeArguments();
356
+ if (typeArguments.length < 2) {
357
+ return;
358
+ }
359
+ const configName = extractStringLiteral(typeArguments[0]);
360
+ if (!configName) {
361
+ logger.warn(`MDX config name is not a string literal in ${file.getFilePath()}`);
362
+ return;
363
+ }
364
+ const componentsArg = typeArguments[1];
365
+ const componentTypeNodes = [];
366
+ if (ts_morph_1.Node.isTupleTypeNode(componentsArg)) {
367
+ componentTypeNodes.push(...componentsArg.getElements());
368
+ }
369
+ else if (ts_morph_1.Node.isArrayTypeNode(componentsArg)) {
370
+ componentTypeNodes.push(componentsArg.getElementTypeNode());
371
+ }
372
+ if (componentTypeNodes.length === 0) {
373
+ configs[configName] = { components: {} };
374
+ return;
375
+ }
376
+ const components = {};
377
+ componentTypeNodes.forEach((componentNode) => {
378
+ const component = extractComponentFromTypeNode(componentNode, file, logger);
379
+ if (!component) {
380
+ return;
381
+ }
382
+ components[component.name] = component.props ? { props: component.props } : {};
383
+ });
384
+ configs[configName] = { components };
385
+ });
386
+ return configs;
387
+ }
388
+ function extractMdxConfigsFromSourceFiles(sourceFiles, logger) {
389
+ const mergedConfigs = {};
390
+ sourceFiles.forEach((file) => {
391
+ const fileConfigs = extractMdxConfigsFromAST(file, logger);
392
+ Object.entries(fileConfigs).forEach(([name, config]) => {
393
+ if (mergedConfigs[name]) {
394
+ logger.warn(`Duplicate MDX config "${name}" found in ${file.getFilePath()}`);
395
+ return;
396
+ }
397
+ mergedConfigs[name] = config;
398
+ });
399
+ });
400
+ return Object.entries(mergedConfigs).map(([name, config]) => ({
401
+ path: `__mdx_config__/${name}`,
402
+ structure: {
403
+ name,
404
+ components: config.components,
405
+ },
406
+ type: "mdxConfig",
407
+ }));
408
+ }
205
409
  // Processes an ATMYAPP export to extract content definitions
206
410
  function processAtmyappExport(atmyappType, file, tsconfigPath, logger) {
207
411
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
@@ -416,5 +620,10 @@ function processFiles(sourceFiles, tsconfigPath, continueOnError, logger) {
416
620
  }
417
621
  });
418
622
  });
623
+ const mdxConfigs = extractMdxConfigsFromSourceFiles(sourceFiles, logger);
624
+ if (mdxConfigs.length > 0) {
625
+ contents.push(...mdxConfigs);
626
+ successCount += mdxConfigs.length;
627
+ }
419
628
  return { contents, errors, successCount, failureCount };
420
629
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atmyapp/cli",
3
- "version": "0.0.7",
3
+ "version": "0.0.9",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "scripts": {
@@ -28,7 +28,7 @@
28
28
  "license": "ISC",
29
29
  "description": "",
30
30
  "devDependencies": {
31
- "@atmyapp/core": "^0.0.6",
31
+ "@atmyapp/core": "^0.0.17",
32
32
  "@types/jest": "^29.5.14",
33
33
  "@typescript-eslint/eslint-plugin": "^8.32.1",
34
34
  "@typescript-eslint/parser": "^8.32.1",
@@ -40,6 +40,7 @@
40
40
  "typescript": "^5.8.3"
41
41
  },
42
42
  "dependencies": {
43
+ "@better-fetch/fetch": "^1.1.18",
43
44
  "chalk": "^4.1.2",
44
45
  "commander": "^14.0.0",
45
46
  "fast-glob": "^3.3.3",