@mearie/codegen 0.0.1-next.3 → 0.0.1-next.4

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/index.js CHANGED
@@ -1,11 +1,11 @@
1
- import { createRequire } from "node:module";
1
+ import { i as __toDynamicImportESM } from "./chunk-CoQ2GtNH.js";
2
2
  import { glob } from "tinyglobby";
3
3
  import picomatch from "picomatch";
4
- import { generateCode } from "@mearie/native";
5
- import { MearieAggregateError, MearieError } from "@mearie/core";
6
4
  import { mkdir, readFile, writeFile } from "node:fs/promises";
7
- import { extractGraphQLSources } from "@mearie/extractor";
5
+ import { extractGraphQLSources, generateCode } from "@mearie/native";
8
6
  import path from "node:path";
7
+ import { configureSync, getAnsiColorFormatter, getConsoleSink, getLogger } from "@logtape/logtape";
8
+ import pc from "picocolors";
9
9
 
10
10
  //#region src/glob.ts
11
11
  /**
@@ -38,6 +38,265 @@ const createMatcher = (patterns) => {
38
38
  };
39
39
  };
40
40
 
41
+ //#endregion
42
+ //#region src/errors.ts
43
+ /**
44
+ * Custom error class for Mearie-specific errors.
45
+ */
46
+ var MearieError = class MearieError extends Error {
47
+ filePath;
48
+ line;
49
+ column;
50
+ constructor(message, filePath, line, column) {
51
+ super(message);
52
+ this.name = "MearieError";
53
+ this.filePath = filePath;
54
+ this.line = line;
55
+ this.column = column;
56
+ }
57
+ static fromNative(data) {
58
+ if (!data || typeof data !== "object") throw new TypeError("Invalid native error data");
59
+ const error = data;
60
+ const filePath = error.location?.file_path;
61
+ const line = error.location?.line;
62
+ const column = error.location?.column;
63
+ return new MearieError(error.message, filePath, line, column);
64
+ }
65
+ };
66
+ /**
67
+ * Aggregate error for multiple Mearie errors.
68
+ */
69
+ var MearieAggregateError = class extends Error {
70
+ errors;
71
+ constructor(errors, message) {
72
+ super(message ?? `${errors.length} error${errors.length > 1 ? "s" : ""} occurred`);
73
+ this.name = "MearieAggregateError";
74
+ this.errors = errors;
75
+ }
76
+ };
77
+ /**
78
+ * Error thrown when `@vue/compiler-sfc` is not installed.
79
+ */
80
+ var MissingVueCompilerError = class extends Error {
81
+ constructor() {
82
+ super(`
83
+ GraphQL operations cannot be extracted from Vue files without @vue/compiler-sfc.
84
+
85
+ Install it with:
86
+ npm install @vue/compiler-sfc
87
+ # or
88
+ pnpm add @vue/compiler-sfc
89
+ # or
90
+ yarn add @vue/compiler-sfc
91
+ `);
92
+ this.name = "MissingVueCompilerError";
93
+ }
94
+ };
95
+ /**
96
+ * Error thrown when svelte compiler is not installed.
97
+ */
98
+ var MissingSvelteCompilerError = class extends Error {
99
+ constructor() {
100
+ super(`
101
+ GraphQL operations cannot be extracted from Svelte files without svelte.
102
+
103
+ Install it with:
104
+ npm install svelte
105
+ # or
106
+ pnpm add svelte
107
+ # or
108
+ yarn add svelte
109
+ `);
110
+ this.name = "MissingSvelteCompilerError";
111
+ }
112
+ };
113
+ /**
114
+ * Error thrown when TypeScript is not installed.
115
+ */
116
+ var MissingTypeScriptError = class extends Error {
117
+ constructor() {
118
+ super(`
119
+ GraphQL operations cannot be extracted from Vue files without typescript.
120
+
121
+ Install it with:
122
+ npm install typescript
123
+ # or
124
+ pnpm add typescript
125
+ # or
126
+ yarn add typescript
127
+ `);
128
+ this.name = "MissingTypeScriptError";
129
+ }
130
+ };
131
+
132
+ //#endregion
133
+ //#region src/loaders.ts
134
+ /**
135
+ * Loads the Vue compiler dynamically.
136
+ * @returns The Vue compiler module.
137
+ * @throws {MissingVueCompilerError} If `@vue/compiler-sfc` is not installed.
138
+ */
139
+ const loadVueCompiler = async () => {
140
+ try {
141
+ return await import("@vue/compiler-sfc");
142
+ } catch {
143
+ throw new MissingVueCompilerError();
144
+ }
145
+ };
146
+ /**
147
+ * Loads TypeScript dynamically.
148
+ * @returns The TypeScript module.
149
+ * @throws {MissingTypeScriptError} If typescript is not installed.
150
+ */
151
+ const loadTypeScript = async () => {
152
+ try {
153
+ return await import("./typescript-dgELwr0O.js").then(__toDynamicImportESM(1));
154
+ } catch {
155
+ throw new MissingTypeScriptError();
156
+ }
157
+ };
158
+ /**
159
+ * Loads the Svelte compiler dynamically.
160
+ * @returns The Svelte compiler module.
161
+ * @throws {MissingSvelteCompilerError} If svelte is not installed.
162
+ */
163
+ const loadSvelteCompiler = async () => {
164
+ try {
165
+ return await import("./compiler-DysSfBLv.js");
166
+ } catch {
167
+ throw new MissingSvelteCompilerError();
168
+ }
169
+ };
170
+
171
+ //#endregion
172
+ //#region src/parsers.ts
173
+ const extractVueScript = async (source) => {
174
+ const [vueCompiler, typescript] = await Promise.all([loadVueCompiler(), loadTypeScript()]);
175
+ vueCompiler.registerTS(() => typescript);
176
+ const { descriptor } = vueCompiler.parse(source.code, { filename: source.filePath });
177
+ const blocks = [];
178
+ if (descriptor.script) blocks.push({
179
+ code: descriptor.script.content,
180
+ filePath: source.filePath,
181
+ startLine: source.startLine + descriptor.script.loc.start.line - 1
182
+ });
183
+ if (descriptor.scriptSetup) blocks.push({
184
+ code: descriptor.scriptSetup.content,
185
+ filePath: source.filePath,
186
+ startLine: source.startLine + descriptor.scriptSetup.loc.start.line - 1
187
+ });
188
+ return blocks;
189
+ };
190
+ const extractSvelteScript = async (source) => {
191
+ const ast = (await loadSvelteCompiler()).parse(source.code);
192
+ const blocks = [];
193
+ if (ast.instance?.content) {
194
+ const code = source.code.slice(ast.instance.content.start, ast.instance.content.end);
195
+ const lineOffset = source.code.slice(0, ast.instance.content.start).split("\n").length - 1;
196
+ blocks.push({
197
+ code,
198
+ filePath: `${source.filePath}.instance.ts`,
199
+ startLine: source.startLine + lineOffset
200
+ });
201
+ }
202
+ if (ast.module?.content) {
203
+ const code = source.code.slice(ast.module.content.start, ast.module.content.end);
204
+ const lineOffset = source.code.slice(0, ast.module.content.start).split("\n").length - 1;
205
+ blocks.push({
206
+ code,
207
+ filePath: `${source.filePath}.module.ts`,
208
+ startLine: source.startLine + lineOffset
209
+ });
210
+ }
211
+ return blocks;
212
+ };
213
+ const extractAstroScripts = (source) => {
214
+ const blocks = [];
215
+ const frontmatterMatch = /^---\s*\n([\s\S]*?)\n---/.exec(source.code);
216
+ if (frontmatterMatch) {
217
+ const lineOffset = source.code.slice(0, frontmatterMatch.index).split("\n").length;
218
+ blocks.push({
219
+ code: frontmatterMatch[1],
220
+ filePath: `${source.filePath}.frontmatter.ts`,
221
+ startLine: source.startLine + lineOffset
222
+ });
223
+ }
224
+ const scriptMatches = source.code.matchAll(/<script\b[^>]*>([\s\S]*?)<\/script>/gi);
225
+ let index = 0;
226
+ for (const match of scriptMatches) {
227
+ const lineOffset = source.code.slice(0, match.index).split("\n").length;
228
+ blocks.push({
229
+ code: match[1],
230
+ filePath: `${source.filePath}.${index}.ts`,
231
+ startLine: source.startLine + lineOffset
232
+ });
233
+ index++;
234
+ }
235
+ return blocks;
236
+ };
237
+ const extractMarkdownCodeBlocks = (source) => {
238
+ const codeBlocks = [];
239
+ const codeBlockRegex = /```(tsx|ts)[^\n]*mearie[^\n]*\n([\s\S]*?)```/g;
240
+ let match;
241
+ let index = 0;
242
+ while ((match = codeBlockRegex.exec(source.code)) !== null) {
243
+ const lineOffset = source.code.slice(0, match.index).split("\n").length;
244
+ codeBlocks.push({
245
+ code: match[2],
246
+ filePath: `${source.filePath}.${index}.${match[1]}`,
247
+ startLine: source.startLine + lineOffset
248
+ });
249
+ index++;
250
+ }
251
+ return codeBlocks;
252
+ };
253
+
254
+ //#endregion
255
+ //#region src/extractor.ts
256
+ const extractGraphQLSources$1 = async (source) => {
257
+ const ext = source.filePath.split(".").pop()?.toLowerCase();
258
+ const sources = [];
259
+ const errors = [];
260
+ const blocks = [];
261
+ try {
262
+ switch (ext) {
263
+ case "vue":
264
+ blocks.push(...await extractVueScript(source));
265
+ break;
266
+ case "svelte":
267
+ blocks.push(...await extractSvelteScript(source));
268
+ break;
269
+ case "astro":
270
+ blocks.push(...extractAstroScripts(source));
271
+ break;
272
+ case "md":
273
+ blocks.push(...extractMarkdownCodeBlocks(source));
274
+ break;
275
+ case "js":
276
+ case "jsx":
277
+ case "ts":
278
+ case "tsx":
279
+ blocks.push(source);
280
+ break;
281
+ default: return {
282
+ sources,
283
+ errors
284
+ };
285
+ }
286
+ } catch (error) {
287
+ throw new MearieError(error instanceof Error ? error.message : String(error), source.filePath);
288
+ }
289
+ for (const block of blocks) {
290
+ const result = extractGraphQLSources(block);
291
+ sources.push(...result.sources);
292
+ errors.push(...result.errors.map((error) => MearieError.fromNative(error)));
293
+ }
294
+ return {
295
+ sources,
296
+ errors
297
+ };
298
+ };
299
+
41
300
  //#endregion
42
301
  //#region src/generator.ts
43
302
  /**
@@ -47,8 +306,8 @@ const createMatcher = (patterns) => {
47
306
  * @throws {Error} If code generation fails.
48
307
  */
49
308
  const generate = (options) => {
50
- const { schemas, documents } = options;
51
- const { sources, errors } = generateCode(schemas, documents);
309
+ const { schemas, documents, config } = options;
310
+ const { sources, errors } = generateCode(schemas, documents, config);
52
311
  return {
53
312
  sources,
54
313
  errors: errors.map((error) => MearieError.fromNative(error))
@@ -57,12 +316,10 @@ const generate = (options) => {
57
316
 
58
317
  //#endregion
59
318
  //#region src/writer.ts
60
- const writeFiles = async (sources) => {
61
- const clientPackageJsonPath = createRequire(path.resolve(process.cwd(), "package.json")).resolve("@mearie/client/package.json");
62
- const meariePackagePath = path.dirname(clientPackageJsonPath);
63
- const clientDir = path.resolve(meariePackagePath, ".mearie", "client");
64
- await mkdir(clientDir, { recursive: true });
65
- await Promise.all(sources.map((source) => writeFile(path.join(clientDir, source.filePath), source.code, "utf8")));
319
+ const writeFiles = async (cwd, sources) => {
320
+ const mearieDir = path.resolve(cwd, ".mearie");
321
+ await mkdir(mearieDir, { recursive: true });
322
+ await Promise.all(sources.map((source) => writeFile(path.join(mearieDir, source.filePath), source.code, "utf8")));
66
323
  };
67
324
 
68
325
  //#endregion
@@ -74,6 +331,14 @@ const writeFiles = async (sources) => {
74
331
  var CodegenContext = class {
75
332
  schemas = /* @__PURE__ */ new Map();
76
333
  documents = /* @__PURE__ */ new Map();
334
+ cwd;
335
+ config;
336
+ constructor(cwd = process.cwd()) {
337
+ this.cwd = cwd;
338
+ }
339
+ setConfig(config) {
340
+ this.config = config;
341
+ }
77
342
  /**
78
343
  * Adds a schema file by reading it.
79
344
  * @param filePath - Schema file path.
@@ -98,7 +363,7 @@ var CodegenContext = class {
98
363
  * @param filePath - Document file path.
99
364
  */
100
365
  async addDocument(filePath) {
101
- const { sources, errors } = await extractGraphQLSources({
366
+ const { sources, errors } = await extractGraphQLSources$1({
102
367
  code: await readFile(filePath, "utf8"),
103
368
  filePath,
104
369
  startLine: 1
@@ -121,12 +386,54 @@ var CodegenContext = class {
121
386
  async generate() {
122
387
  const { sources, errors } = generate({
123
388
  schemas: [...this.schemas.values()],
124
- documents: [...this.documents.values()].flat()
389
+ documents: [...this.documents.values()].flat(),
390
+ config: this.config
125
391
  });
126
- await writeFiles(sources);
392
+ await writeFiles(this.cwd, sources);
127
393
  if (errors.length > 0) throw new MearieAggregateError(errors);
128
394
  }
129
395
  };
130
396
 
131
397
  //#endregion
132
- export { CodegenContext, createMatcher, findFiles, generate };
398
+ //#region src/logger.ts
399
+ configureSync({
400
+ reset: true,
401
+ sinks: { console: getConsoleSink({ formatter: getAnsiColorFormatter({
402
+ level: "FULL",
403
+ timestamp: "time",
404
+ category: (category) => `💬 ${category.join("·")}`
405
+ }) }) },
406
+ loggers: [{
407
+ category: "mearie",
408
+ lowestLevel: "info",
409
+ sinks: ["console"]
410
+ }, {
411
+ category: ["logtape", "meta"],
412
+ lowestLevel: "warning",
413
+ sinks: ["console"]
414
+ }]
415
+ });
416
+ const logger = getLogger(["mearie"]);
417
+ const formatMearieError = (error) => {
418
+ const parts = [
419
+ error.filePath,
420
+ error.line,
421
+ error.column
422
+ ].filter((part) => part !== void 0 && part !== null).map(String);
423
+ const location = parts.length > 0 ? parts.join(":") : "";
424
+ if (location) return `${pc.bold(error.message)} ${pc.cyan(pc.underline(location))}`;
425
+ return pc.bold(error.message);
426
+ };
427
+ /**
428
+ * Reports an error using the provided logger.
429
+ * @param logger - The logger to use.
430
+ * @param error - The error to report.
431
+ */
432
+ const report = (logger$1, error) => {
433
+ if (error instanceof MearieAggregateError) for (const err of error.errors) logger$1.error(formatMearieError(err));
434
+ else if (error instanceof MearieError) logger$1.error(formatMearieError(error));
435
+ else logger$1.error("{error}", { error });
436
+ };
437
+
438
+ //#endregion
439
+ export { CodegenContext, createMatcher, findFiles, logger, report };