@nestia/editor 14.0.0 → 14.0.2

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.
Files changed (39) hide show
  1. package/README.md +1 -1
  2. package/dist/assets/{index-C1g1lYbd.js → index-rFcfd8RQ.js} +138 -137
  3. package/dist/index.html +1 -1
  4. package/lib/NestiaEditorApplication.d.ts +10 -0
  5. package/lib/NestiaEditorApplication.js +20 -4
  6. package/lib/NestiaEditorApplication.js.map +1 -1
  7. package/lib/NestiaEditorApplication.mjs +17 -1
  8. package/lib/NestiaEditorIframe.d.ts +31 -0
  9. package/lib/NestiaEditorIframe.js +22 -4
  10. package/lib/NestiaEditorIframe.js.map +1 -1
  11. package/lib/NestiaEditorIframe.mjs +49 -10
  12. package/lib/NestiaEditorModule.d.ts +46 -0
  13. package/lib/NestiaEditorModule.js +120 -30
  14. package/lib/NestiaEditorModule.js.map +1 -1
  15. package/lib/NestiaEditorModule.mjs +43 -23
  16. package/lib/NestiaEditorUploader.d.ts +19 -0
  17. package/lib/NestiaEditorUploader.js +15 -0
  18. package/lib/NestiaEditorUploader.js.map +1 -1
  19. package/lib/NestiaEditorUploader.mjs +18 -6
  20. package/lib/internal/NestiaEditorArchiver.d.ts +35 -3
  21. package/lib/internal/NestiaEditorArchiver.js +60 -8
  22. package/lib/internal/NestiaEditorArchiver.js.map +1 -1
  23. package/lib/internal/NestiaEditorArchiver.mjs +25 -5
  24. package/lib/internal/NestiaEditorComposer.d.ts +80 -0
  25. package/lib/internal/NestiaEditorComposer.js +33 -0
  26. package/lib/internal/NestiaEditorComposer.js.map +1 -1
  27. package/lib/internal/NestiaEditorComposer.mjs +8 -2
  28. package/lib/internal/NestiaEditorFileUploader.d.ts +21 -0
  29. package/lib/internal/NestiaEditorFileUploader.js +12 -0
  30. package/lib/internal/NestiaEditorFileUploader.js.map +1 -1
  31. package/lib/internal/NestiaEditorFileUploader.mjs +12 -0
  32. package/package.json +6 -5
  33. package/src/NestiaEditorApplication.tsx +19 -3
  34. package/src/NestiaEditorIframe.tsx +61 -6
  35. package/src/NestiaEditorModule.ts +139 -39
  36. package/src/NestiaEditorUploader.tsx +28 -0
  37. package/src/internal/NestiaEditorArchiver.ts +65 -10
  38. package/src/internal/NestiaEditorComposer.ts +96 -0
  39. package/src/internal/NestiaEditorFileUploader.tsx +21 -0
@@ -1,4 +1,6 @@
1
- import { strToU8, zipSync } from "fflate";
1
+ import { Zip, ZipDeflate, strToU8 } from "fflate";
2
+
3
+ import { NESTIA_EDITOR_DEFAULT_PACKAGE } from "./NestiaEditorDefaultPackage";
2
4
 
3
5
  /**
4
6
  * Archives a composed project into a zip file and hands it to the browser.
@@ -8,21 +10,74 @@ import { strToU8, zipSync } from "fflate";
8
10
  * WebContainer cannot execute. The editor therefore delivers the composed
9
11
  * project as a downloadable zip archive instead of an embedded StackBlitz
10
12
  * workspace.
13
+ *
14
+ * @evidence contracts/common.md#principled-implementation Packing is a synchronous zip of UTF-8 encoded entries through `fflate`, naming derives from the package name with a fixed character whitelist, and the download creates an object URL, clicks an anchor, and revokes the URL later.
15
+ * @evidence contracts/common.md#clear-and-simple-design Three operations, each one browser or zip concern, in one namespace with no shared state.
16
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The archive is built with the library's public functions and the download uses the standard anchor mechanism; nothing is patched.
17
+ * @evidence contracts/common.md#meaningful-documentation The namespace prose explains why the editor delivers a zip archive rather than an embedded workspace.
11
18
  */
12
19
  export namespace NestiaEditorArchiver {
13
- /** Pack the composed project files into a zip archive. */
20
+ /**
21
+ * Pack the composed project files into a zip archive.
22
+ *
23
+ * @evidence contracts/common.md#principled-implementation Each own file key names a synchronous ZipDeflate stream added to Zip. Filenames are values rather than dictionary properties, preserving prototype-related names without changing an object's prototype. UTF-8 encoding preserves text; ending the archive emits its directory, including for an empty project.
24
+ * @evidence contracts/common.md#clear-and-simple-design One loop supplies files to the public synchronous compression streams; the callback collects chunks which are copied once into the returned archive.
25
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts It archives exactly the given files; no entry is added, filtered, or renamed.
26
+ * @evidence contracts/common.md#meaningful-documentation The comment states the input and output.
27
+ */
14
28
  export const pack = (files: Record<string, string>): Uint8Array => {
15
- const entries: Record<string, Uint8Array> = {};
16
- for (const [key, value] of Object.entries(files))
17
- entries[key] = strToU8(value);
18
- return zipSync(entries);
29
+ const chunks: Uint8Array[] = [];
30
+ const archive = new Zip((error, chunk) => {
31
+ if (error) throw error;
32
+ chunks.push(chunk);
33
+ });
34
+ for (const [key, value] of Object.entries(files)) {
35
+ const entry = new ZipDeflate(key);
36
+ archive.add(entry);
37
+ entry.push(strToU8(value), true);
38
+ }
39
+ archive.end();
40
+ const output = new Uint8Array(
41
+ chunks.reduce((length, chunk) => length + chunk.length, 0),
42
+ );
43
+ let offset = 0;
44
+ for (const chunk of chunks) {
45
+ output.set(chunk, offset);
46
+ offset += chunk.length;
47
+ }
48
+ return output;
49
+ };
50
+
51
+ /**
52
+ * Compose a safe archive file name from a package name.
53
+ *
54
+ * A leading `@` is dropped and every run of characters outside letters,
55
+ * digits, `.`, `_`, and `-` becomes one `-`. A name with nothing left but
56
+ * dots, such as an empty package name, has no usable base for the archive, so
57
+ * the default package name is used instead. Other names retain their dots,
58
+ * including a leading dot.
59
+ *
60
+ * @evidence contracts/common.md#principled-implementation Dropping the `@` and replacing runs of characters outside the whitelist with one `-` yields a file name without path separators. Empty or dots-only bases use the default package name; otherwise dots are retained, so this is not a general rejection of hidden filenames or a validator of npm package names.
61
+ * @evidence contracts/common.md#clear-and-simple-design One private helper applies the character rule to the package name and to the default, so the rule exists once.
62
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The rule applies to every input; the only special case is the empty-name guard, which follows from the safe-name requirement.
63
+ * @evidence contracts/common.md#meaningful-documentation The comment states the character rule and the dots-only fallback.
64
+ */
65
+ export const name = (packageName: string): string => {
66
+ const base: string = compose(packageName);
67
+ return `${/^\.*$/.test(base) ? compose(NESTIA_EDITOR_DEFAULT_PACKAGE) : base}.zip`;
19
68
  };
20
69
 
21
- /** Compose a safe archive file name from a package name. */
22
- export const name = (packageName: string): string =>
23
- `${packageName.replace(/^@/, "").replace(/[^A-Za-z0-9._-]+/g, "-")}.zip`;
70
+ const compose = (packageName: string): string =>
71
+ packageName.replace(/^@/, "").replace(/[^A-Za-z0-9._-]+/g, "-");
24
72
 
25
- /** Trigger a browser download of the packed archive. */
73
+ /**
74
+ * Trigger a browser download of the packed archive.
75
+ *
76
+ * @evidence contracts/common.md#principled-implementation A Blob of the packed bytes is exposed through an object URL and an anchor with the `download` attribute is clicked, which is the browser's standard way to save generated content; the URL is revoked after 30 seconds so its memory is released.
77
+ * @evidence contracts/common.md#clear-and-simple-design One function, kept apart from `pack` so packing stays testable outside a browser.
78
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts It uses the standard DOM and URL APIs; the delayed revocation is not a retry or a compensation.
79
+ * @evidence contracts/common.md#meaningful-documentation The comment states that it triggers a browser download of the packed archive.
80
+ */
26
81
  export const download = (props: {
27
82
  name: string;
28
83
  files: Record<string, string>;
@@ -11,26 +11,108 @@ import * as prettierTsPlugin from "prettier/plugins/typescript";
11
11
  import { format } from "prettier/standalone";
12
12
  import { IValidation } from "typia";
13
13
 
14
+ /**
15
+ * Composes the files of a project from an OpenAPI document.
16
+ *
17
+ * It validates and converts the document with `@nestia/migrate`, then formats
18
+ * the TypeScript files with Prettier's standalone build.
19
+ *
20
+ * @evidence contracts/common.md#principled-implementation The composer delegates conversion to `NestiaMigrateApplication`, which owns the OpenAPI semantics, and formats each `.ts` output with Prettier; a file that fails to format keeps its unformatted text.
21
+ * @evidence contracts/common.md#clear-and-simple-design One namespace with two public entry points that select the migration mode and retain the legacy workspace launch metadata; the shared flow is one private curried function.
22
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts Conversion and formatting use the public APIs of `@nestia/migrate` and Prettier; a formatting failure is logged and the file is kept as generated.
23
+ * @evidence contracts/common.md#meaningful-documentation The comment states what the composer produces and which libraries do the work.
24
+ */
14
25
  export namespace NestiaEditorComposer {
26
+ /**
27
+ * Input of the composer: the OpenAPI document, the generator options, and the
28
+ * package name.
29
+ *
30
+ * The internal `files` member bypasses conversion and returns the given files
31
+ * unchanged.
32
+ *
33
+ * @evidence contracts/common.md#principled-implementation The fields are the migrate options the editor exposes plus the document, and `files` lets a caller supply an already composed project.
34
+ * @evidence contracts/common.md#clear-and-simple-design A flat property record; the document type is the union of the supported OpenAPI and Swagger versions.
35
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts No field is defaulted here; the callers own the defaults.
36
+ * @evidence contracts/common.md#meaningful-documentation The comment states the inputs and the internal member.
37
+ */
15
38
  export interface IProps {
39
+ /** OpenAPI or Swagger source to validate before conversion. */
16
40
  document:
17
41
  | SwaggerV2.IDocument
18
42
  | OpenApiV3.IDocument
19
43
  | OpenApiV3_1.IDocument
20
44
  | OpenApiV3_2.IDocument;
45
+
46
+ /** Include generated E2E functions. */
21
47
  e2e: boolean;
48
+
49
+ /** Group generated parameters into a keyword object. */
22
50
  keyword: boolean;
51
+
52
+ /** Include SDK mockup simulators. */
23
53
  simulate: boolean;
54
+
55
+ /** Package identity passed to the migration generator. */
24
56
  package?: string;
57
+
25
58
  /** @internal */
26
59
  files?: Record<string, string>;
27
60
  }
61
+ /**
62
+ * Output of the composer: the files, the files to open, the start script, and
63
+ * the skipped operations.
64
+ *
65
+ * @evidence contracts/common.md#principled-implementation The files carry the downloadable project and skipped exposes incomplete conversion. openFile and startScript are legacy workspace metadata with no reader in the current zip UI.
66
+ * @evidence contracts/common.md#clear-and-simple-design A flat property record without behavior.
67
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts Every member is produced by the composer or the migrate application; none is a fixture value.
68
+ * @evidence contracts/common.md#meaningful-documentation The comment names the members and the `skipped` member documents itself.
69
+ */
28
70
  export interface IOutput {
71
+ /** Relative project paths mapped to UTF-8 text. */
29
72
  files: Record<string, string>;
73
+
74
+ /** Legacy comma-separated workspace editor entry paths. */
30
75
  openFile: string;
76
+
77
+ /** Legacy workspace launch commands; zip downloads do not execute them. */
31
78
  startScript: string[];
79
+
80
+ /**
81
+ * Operations `@nestia/migrate` could not convert, left out of the files.
82
+ *
83
+ * The CLI prints them; the editor reports them to its user, so a project
84
+ * lacking an operation never passes for a complete one.
85
+ */
86
+ skipped: ISkipped[];
87
+ }
88
+ /**
89
+ * An operation that could not be converted: its upper-case HTTP method, its
90
+ * path, and the reasons.
91
+ *
92
+ * @evidence contracts/common.md#principled-implementation The migrate application reports errors by method, path, and messages, and the composer normalizes the method to upper case for display.
93
+ * @evidence contracts/common.md#clear-and-simple-design Three fields with no behavior.
94
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The values are copied from the migrate errors.
95
+ * @evidence contracts/common.md#meaningful-documentation The comment states each field.
96
+ */
97
+ export interface ISkipped {
98
+ /** Upper-case HTTP method identifying the omitted operation. */
99
+ method: string;
100
+
101
+ /** OpenAPI path identifying the omitted operation. */
102
+ path: string;
103
+
104
+ /** Conversion diagnostics supplied by the migrate application. */
105
+ messages: string[];
32
106
  }
33
107
 
108
+ /**
109
+ * Composes a NestJS project from an OpenAPI document.
110
+ *
111
+ * @evidence contracts/common.md#principled-implementation It runs the shared flow with the migrate application's `nest` output, the `README.md,test/start.ts` files to open, and the `build:test,test` start script.
112
+ * @evidence contracts/common.md#clear-and-simple-design A one-expression binding of the shared flow.
113
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The mode selects the public migrate operation. Returned launch metadata comes from the former embedded workspace flow; zip delivery does not read or execute it.
114
+ * @evidence contracts/common.md#meaningful-documentation The comment names the project kind produced.
115
+ */
34
116
  export const nest = (props: IProps): Promise<IValidation<IOutput>> =>
35
117
  compose({
36
118
  openFile: "README.md,test/start.ts",
@@ -38,6 +120,14 @@ export namespace NestiaEditorComposer {
38
120
  migrate: (app) => app.nest(props),
39
121
  })(props);
40
122
 
123
+ /**
124
+ * Composes a software development kit project from an OpenAPI document.
125
+ *
126
+ * @evidence contracts/common.md#principled-implementation It runs the shared flow with the migrate application's `sdk` output, the `README.md,test/start.ts` files to open, and the `swagger` and `hello` start scripts.
127
+ * @evidence contracts/common.md#clear-and-simple-design A one-expression binding of the shared flow.
128
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The mode selects the public migrate operation. Returned launch metadata comes from the former embedded workspace flow; zip delivery does not read or execute it.
129
+ * @evidence contracts/common.md#meaningful-documentation The comment names the project kind produced.
130
+ */
41
131
  export const sdk = async (props: IProps): Promise<IValidation<IOutput>> =>
42
132
  compose({
43
133
  openFile: "README.md,test/start.ts",
@@ -59,6 +149,7 @@ export namespace NestiaEditorComposer {
59
149
  files: props.files,
60
150
  openFile: config.openFile,
61
151
  startScript: config.startScript,
152
+ skipped: [],
62
153
  },
63
154
  };
64
155
  const result: IValidation<NestiaMigrateApplication> =
@@ -83,6 +174,11 @@ export namespace NestiaEditorComposer {
83
174
  files,
84
175
  openFile: config.openFile,
85
176
  startScript: config.startScript,
177
+ skipped: app.getData().errors.map((error) => ({
178
+ method: error.method.toUpperCase(),
179
+ path: error.path,
180
+ messages: error.messages,
181
+ })),
86
182
  },
87
183
  } satisfies IValidation<IOutput>;
88
184
  };
@@ -3,6 +3,18 @@ import { load } from "js-yaml";
3
3
  import React from "react";
4
4
  import FileUpload, { type ExtendedFileProps } from "react-mui-fileuploader";
5
5
 
6
+ /**
7
+ * A file picker that reads an OpenAPI document from a JSON or YAML file.
8
+ *
9
+ * The last chosen file is read and parsed by its extension, and the result is passed to `onChange` with the parsed document, or with an error message when the content does not parse. Clearing the selection reports `null` for both.
10
+ *
11
+ * A file-reading failure rejects the uploader callback before parsing; it is not reported through `onChange`. Parsing reports content without validating its OpenAPI shape; the composer performs that validation.
12
+ *
13
+ * @evidence contracts/common.md#principled-implementation The file is decoded as UTF-8 text and parsed with `JSON.parse` for a `json` extension and with `js-yaml` otherwise; a parse failure is reported with the message for the format, and only the last chosen file is kept, matching the single-file picker.
14
+ * @evidence contracts/common.md#clear-and-simple-design One component wraps the third-party uploader and owns only reading and parsing; the form around it belongs to `NestiaEditorUploader`.
15
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The parser is chosen by the file extension alone; no document name or content is special-cased.
16
+ * @evidence contracts/common.md#meaningful-documentation The comment states which file is read, how it is parsed, and what `onChange` receives in each case.
17
+ */
6
18
  export function NestiaEditorFileUploader(
7
19
  props: NestiaEditorFileUploader.IProps,
8
20
  ) {
@@ -51,8 +63,17 @@ export function NestiaEditorFileUploader(
51
63
  />
52
64
  );
53
65
  }
66
+ /**
67
+ * Properties of {@link NestiaEditorFileUploader}.
68
+ *
69
+ * @evidence contracts/common.md#principled-implementation The namespace holds the property type of the component with the same name.
70
+ * @evidence contracts/common.md#clear-and-simple-design It contains one interface with one callback.
71
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts It adds no behavior.
72
+ * @evidence contracts/common.md#meaningful-documentation The comment names the component the properties belong to.
73
+ */
54
74
  export namespace NestiaEditorFileUploader {
55
75
  export interface IProps {
76
+ /** Receives parsed file content, parse failures, or null/null when cleared. */
56
77
  onChange: (
57
78
  swagger:
58
79
  | SwaggerV2.IDocument