@nestia/editor 12.0.0-rc.2 → 12.0.0-rc.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.
Files changed (100) hide show
  1. package/LICENSE +21 -21
  2. package/dist/assets/index-Wyu3BnMf.js +4289 -0
  3. package/dist/index.html +19 -19
  4. package/lib/NestiaEditorApplication.mjs +66 -3
  5. package/lib/NestiaEditorApplication.mjs.map +1 -1
  6. package/lib/NestiaEditorIframe.js +11 -17
  7. package/lib/NestiaEditorIframe.js.map +1 -1
  8. package/lib/NestiaEditorIframe.mjs +159 -3
  9. package/lib/NestiaEditorIframe.mjs.map +1 -1
  10. package/lib/NestiaEditorModule.mjs +51 -3
  11. package/lib/NestiaEditorModule.mjs.map +1 -1
  12. package/lib/NestiaEditorUploader.js +4 -11
  13. package/lib/NestiaEditorUploader.js.map +1 -1
  14. package/lib/NestiaEditorUploader.mjs +129 -3
  15. package/lib/NestiaEditorUploader.mjs.map +1 -1
  16. package/lib/index.mjs +4 -2
  17. package/lib/internal/NestiaEditorArchiver.d.ts +20 -0
  18. package/lib/internal/NestiaEditorArchiver.js +38 -0
  19. package/lib/internal/NestiaEditorArchiver.js.map +1 -0
  20. package/lib/internal/NestiaEditorArchiver.mjs +24 -0
  21. package/lib/internal/NestiaEditorArchiver.mjs.map +1 -0
  22. package/lib/internal/NestiaEditorComposer.mjs +52 -3
  23. package/lib/internal/NestiaEditorComposer.mjs.map +1 -1
  24. package/lib/internal/NestiaEditorFileUploader.mjs +43 -3
  25. package/lib/internal/NestiaEditorFileUploader.mjs.map +1 -1
  26. package/lib/main.mjs +9 -3
  27. package/lib/main.mjs.map +1 -1
  28. package/package.json +9 -12
  29. package/src/NestiaEditorApplication.tsx +94 -94
  30. package/src/NestiaEditorIframe.tsx +258 -245
  31. package/src/NestiaEditorModule.ts +136 -136
  32. package/src/NestiaEditorUploader.tsx +146 -154
  33. package/src/index.ts +3 -3
  34. package/src/internal/NestiaEditorArchiver.ts +43 -0
  35. package/src/internal/NestiaEditorComposer.ts +89 -89
  36. package/src/internal/NestiaEditorFileUploader.tsx +65 -65
  37. package/src/main.tsx +10 -10
  38. package/src/typings/react-mui-fileuploader.d.ts +27 -27
  39. package/src/vite-env.d.ts +1 -1
  40. package/README.md +0 -93
  41. package/dist/assets/index-tCs1FGcC.js +0 -4318
  42. package/lib/NestiaEditorApplication2.mjs +0 -86
  43. package/lib/NestiaEditorApplication2.mjs.map +0 -1
  44. package/lib/NestiaEditorIframe2.mjs +0 -139
  45. package/lib/NestiaEditorIframe2.mjs.map +0 -1
  46. package/lib/NestiaEditorModule2.mjs +0 -124
  47. package/lib/NestiaEditorModule2.mjs.map +0 -1
  48. package/lib/NestiaEditorUploader2.mjs +0 -90
  49. package/lib/NestiaEditorUploader2.mjs.map +0 -1
  50. package/lib/_virtual/NestiaEditorApplication.mjs +0 -4
  51. package/lib/_virtual/NestiaEditorApplication.mjs.map +0 -1
  52. package/lib/_virtual/NestiaEditorComposer.mjs +0 -4
  53. package/lib/_virtual/NestiaEditorComposer.mjs.map +0 -1
  54. package/lib/_virtual/NestiaEditorFileUploader.mjs +0 -4
  55. package/lib/_virtual/NestiaEditorFileUploader.mjs.map +0 -1
  56. package/lib/_virtual/NestiaEditorIframe.mjs +0 -4
  57. package/lib/_virtual/NestiaEditorIframe.mjs.map +0 -1
  58. package/lib/_virtual/NestiaEditorModule.mjs +0 -4
  59. package/lib/_virtual/NestiaEditorModule.mjs.map +0 -1
  60. package/lib/_virtual/NestiaEditorUploader.mjs +0 -4
  61. package/lib/_virtual/NestiaEditorUploader.mjs.map +0 -1
  62. package/lib/_virtual/_commonjsHelpers.mjs +0 -35
  63. package/lib/_virtual/_commonjsHelpers.mjs.map +0 -1
  64. package/lib/_virtual/_js-yaml.mjs +0 -7
  65. package/lib/_virtual/_js-yaml.mjs.map +0 -1
  66. package/lib/_virtual/_node_fs.mjs +0 -7
  67. package/lib/_virtual/_node_fs.mjs.map +0 -1
  68. package/lib/_virtual/_react-mui-fileuploader.mjs +0 -7
  69. package/lib/_virtual/_react-mui-fileuploader.mjs.map +0 -1
  70. package/lib/_virtual/_react.mjs +0 -7
  71. package/lib/_virtual/_react.mjs.map +0 -1
  72. package/lib/_virtual/client.mjs +0 -7
  73. package/lib/_virtual/client.mjs.map +0 -1
  74. package/lib/_virtual/estree.mjs +0 -7
  75. package/lib/_virtual/estree.mjs.map +0 -1
  76. package/lib/_virtual/index.mjs +0 -4
  77. package/lib/_virtual/index.mjs.map +0 -1
  78. package/lib/_virtual/jsx-runtime.mjs +0 -7
  79. package/lib/_virtual/jsx-runtime.mjs.map +0 -1
  80. package/lib/_virtual/main.mjs +0 -4
  81. package/lib/_virtual/main.mjs.map +0 -1
  82. package/lib/_virtual/material.mjs +0 -7
  83. package/lib/_virtual/material.mjs.map +0 -1
  84. package/lib/_virtual/migrate.mjs +0 -7
  85. package/lib/_virtual/migrate.mjs.map +0 -1
  86. package/lib/_virtual/sdk.mjs +0 -7
  87. package/lib/_virtual/sdk.mjs.map +0 -1
  88. package/lib/_virtual/standalone.mjs +0 -7
  89. package/lib/_virtual/standalone.mjs.map +0 -1
  90. package/lib/_virtual/typescript.mjs +0 -7
  91. package/lib/_virtual/typescript.mjs.map +0 -1
  92. package/lib/index.mjs.map +0 -1
  93. package/lib/index2.mjs +0 -35
  94. package/lib/index2.mjs.map +0 -1
  95. package/lib/internal/NestiaEditorComposer2.mjs +0 -110
  96. package/lib/internal/NestiaEditorComposer2.mjs.map +0 -1
  97. package/lib/internal/NestiaEditorFileUploader2.mjs +0 -51
  98. package/lib/internal/NestiaEditorFileUploader2.mjs.map +0 -1
  99. package/lib/main2.mjs +0 -16
  100. package/lib/main2.mjs.map +0 -1
@@ -1,136 +1,136 @@
1
- import type {
2
- OpenApiV3,
3
- OpenApiV3_1,
4
- OpenApiV3_2,
5
- SwaggerV2,
6
- } from "@typia/interface";
7
- import * as fs from "fs";
8
-
9
- export namespace NestiaEditorModule {
10
- export const setup = async (props: {
11
- path: string;
12
- application: INestApplication;
13
- swagger:
14
- | string
15
- | SwaggerV2.IDocument
16
- | OpenApiV3.IDocument
17
- | OpenApiV3_1.IDocument
18
- | OpenApiV3_2.IDocument;
19
- package?: string;
20
- simulate?: boolean;
21
- e2e?: boolean;
22
- }): Promise<void> => {
23
- const prefix: string =
24
- "/" +
25
- [getGlobalPrefix(props.application), props.path]
26
- .join("/")
27
- .split("/")
28
- .filter((str) => str.length !== 0)
29
- .join("/");
30
- const adaptor: INestHttpAdaptor = props.application.getHttpAdapter();
31
- const staticFiles: IStaticFile[] = [
32
- {
33
- path: "/index.html",
34
- type: "text/html",
35
- content: await getIndex(props),
36
- },
37
- {
38
- path: "/swagger.json",
39
- type: "application/json",
40
- content: JSON.stringify(
41
- typeof props.swagger === "string"
42
- ? await getSwagger(props.swagger)
43
- : props.swagger,
44
- null,
45
- 2,
46
- ),
47
- },
48
- await getJavaScript(),
49
- ];
50
- for (const f of staticFiles) {
51
- adaptor.get(prefix + f.path, (_: any, res: any) => {
52
- res.type(f.type);
53
- return res.send(f.content);
54
- });
55
- }
56
- for (const p of ["", "/"])
57
- adaptor.get(prefix + p, (_: any, res: any) => {
58
- return res.redirect(prefix + "/index.html");
59
- });
60
- };
61
-
62
- const getGlobalPrefix = (app: INestApplication): string =>
63
- typeof (app as any).config?.globalPrefix === "string"
64
- ? (app as any).config.globalPrefix
65
- : "";
66
- }
67
-
68
- interface INestApplication {
69
- use(...args: any[]): this;
70
- getUrl(): Promise<string>;
71
- getHttpAdapter(): INestHttpAdaptor;
72
- setGlobalPrefix(prefix: string, options?: any): this;
73
- }
74
- interface INestHttpAdaptor {
75
- getType(): string;
76
- close(): any;
77
- init?(): Promise<void>;
78
- get: Function;
79
- post: Function;
80
- put: Function;
81
- patch: Function;
82
- delete: Function;
83
- head: Function;
84
- all: Function;
85
- }
86
- interface IStaticFile {
87
- path: string;
88
- type: string;
89
- content: string;
90
- }
91
-
92
- const getIndex = async (props: {
93
- package?: string;
94
- simulate?: boolean;
95
- e2e?: boolean;
96
- }): Promise<string> => {
97
- const content: string = await fs.promises.readFile(
98
- `${__dirname}/../dist/index.html`,
99
- "utf8",
100
- );
101
- return content
102
- .replace(
103
- `"@ORGANIZATION/PROJECT"`,
104
- JSON.stringify(props.package ?? "@ORGANIZATION/PROJECT"),
105
- )
106
- .replace("window.simulate = false", `window.simulate = ${!!props.simulate}`)
107
- .replace("window.e2e = false", `window.e2e = ${!!props.e2e}`);
108
- };
109
-
110
- const getJavaScript = async (): Promise<IStaticFile> => {
111
- const directory: string[] = await fs.promises.readdir(
112
- `${__dirname}/../dist/assets`,
113
- );
114
- const path: string | undefined = directory[0];
115
- if (path === undefined)
116
- throw new Error("Unreachable code, no JS file exists.");
117
- return {
118
- path: `/assets/${path}`,
119
- type: "application/javascript",
120
- content: await fs.promises.readFile(
121
- `${__dirname}/../dist/assets/${path}`,
122
- "utf8",
123
- ),
124
- };
125
- };
126
-
127
- const getSwagger = async (
128
- url: string,
129
- ): Promise<
130
- SwaggerV2.IDocument | OpenApiV3.IDocument | OpenApiV3_1.IDocument
131
- > => {
132
- const response: Response = await fetch(url);
133
- if (response.status !== 200)
134
- throw new Error(`Failed to fetch Swagger document from ${url}`);
135
- return response.json();
136
- };
1
+ import type {
2
+ OpenApiV3,
3
+ OpenApiV3_1,
4
+ OpenApiV3_2,
5
+ SwaggerV2,
6
+ } from "@typia/interface";
7
+ import * as fs from "fs";
8
+
9
+ export namespace NestiaEditorModule {
10
+ export const setup = async (props: {
11
+ path: string;
12
+ application: INestApplication;
13
+ swagger:
14
+ | string
15
+ | SwaggerV2.IDocument
16
+ | OpenApiV3.IDocument
17
+ | OpenApiV3_1.IDocument
18
+ | OpenApiV3_2.IDocument;
19
+ package?: string;
20
+ simulate?: boolean;
21
+ e2e?: boolean;
22
+ }): Promise<void> => {
23
+ const prefix: string =
24
+ "/" +
25
+ [getGlobalPrefix(props.application), props.path]
26
+ .join("/")
27
+ .split("/")
28
+ .filter((str) => str.length !== 0)
29
+ .join("/");
30
+ const adaptor: INestHttpAdaptor = props.application.getHttpAdapter();
31
+ const staticFiles: IStaticFile[] = [
32
+ {
33
+ path: "/index.html",
34
+ type: "text/html",
35
+ content: await getIndex(props),
36
+ },
37
+ {
38
+ path: "/swagger.json",
39
+ type: "application/json",
40
+ content: JSON.stringify(
41
+ typeof props.swagger === "string"
42
+ ? await getSwagger(props.swagger)
43
+ : props.swagger,
44
+ null,
45
+ 2,
46
+ ),
47
+ },
48
+ await getJavaScript(),
49
+ ];
50
+ for (const f of staticFiles) {
51
+ adaptor.get(prefix + f.path, (_: any, res: any) => {
52
+ res.type(f.type);
53
+ return res.send(f.content);
54
+ });
55
+ }
56
+ for (const p of ["", "/"])
57
+ adaptor.get(prefix + p, (_: any, res: any) => {
58
+ return res.redirect(prefix + "/index.html");
59
+ });
60
+ };
61
+
62
+ const getGlobalPrefix = (app: INestApplication): string =>
63
+ typeof (app as any).config?.globalPrefix === "string"
64
+ ? (app as any).config.globalPrefix
65
+ : "";
66
+ }
67
+
68
+ interface INestApplication {
69
+ use(...args: any[]): this;
70
+ getUrl(): Promise<string>;
71
+ getHttpAdapter(): INestHttpAdaptor;
72
+ setGlobalPrefix(prefix: string, options?: any): this;
73
+ }
74
+ interface INestHttpAdaptor {
75
+ getType(): string;
76
+ close(): any;
77
+ init?(): Promise<void>;
78
+ get: Function;
79
+ post: Function;
80
+ put: Function;
81
+ patch: Function;
82
+ delete: Function;
83
+ head: Function;
84
+ all: Function;
85
+ }
86
+ interface IStaticFile {
87
+ path: string;
88
+ type: string;
89
+ content: string;
90
+ }
91
+
92
+ const getIndex = async (props: {
93
+ package?: string;
94
+ simulate?: boolean;
95
+ e2e?: boolean;
96
+ }): Promise<string> => {
97
+ const content: string = await fs.promises.readFile(
98
+ `${__dirname}/../dist/index.html`,
99
+ "utf8",
100
+ );
101
+ return content
102
+ .replace(
103
+ `"@ORGANIZATION/PROJECT"`,
104
+ JSON.stringify(props.package ?? "@ORGANIZATION/PROJECT"),
105
+ )
106
+ .replace("window.simulate = false", `window.simulate = ${!!props.simulate}`)
107
+ .replace("window.e2e = false", `window.e2e = ${!!props.e2e}`);
108
+ };
109
+
110
+ const getJavaScript = async (): Promise<IStaticFile> => {
111
+ const directory: string[] = await fs.promises.readdir(
112
+ `${__dirname}/../dist/assets`,
113
+ );
114
+ const path: string | undefined = directory[0];
115
+ if (path === undefined)
116
+ throw new Error("Unreachable code, no JS file exists.");
117
+ return {
118
+ path: `/assets/${path}`,
119
+ type: "application/javascript",
120
+ content: await fs.promises.readFile(
121
+ `${__dirname}/../dist/assets/${path}`,
122
+ "utf8",
123
+ ),
124
+ };
125
+ };
126
+
127
+ const getSwagger = async (
128
+ url: string,
129
+ ): Promise<
130
+ SwaggerV2.IDocument | OpenApiV3.IDocument | OpenApiV3_1.IDocument
131
+ > => {
132
+ const response: Response = await fetch(url);
133
+ if (response.status !== 200)
134
+ throw new Error(`Failed to fetch Swagger document from ${url}`);
135
+ return response.json();
136
+ };
@@ -1,154 +1,146 @@
1
- import {
2
- Button,
3
- FormControl,
4
- FormControlLabel,
5
- FormLabel,
6
- Radio,
7
- RadioGroup,
8
- Switch,
9
- TextField,
10
- } from "@mui/material";
11
- import StackBlitzSDK from "@stackblitz/sdk";
12
- import { OpenApiV3, OpenApiV3_1, SwaggerV2 } from "@typia/interface";
13
- import React from "react";
14
-
15
- import { NestiaEditorComposer } from "./internal/NestiaEditorComposer";
16
- import { NestiaEditorFileUploader } from "./internal/NestiaEditorFileUploader";
17
-
18
- export function NestiaEditorUploader(props: NestiaEditorUploader.IProps) {
19
- // PARAMETERS
20
- const [mode, setMode] = React.useState<"nest" | "sdk">("sdk");
21
- const [keyword, setKeyword] = React.useState(true);
22
- const [simulate, setSimulate] = React.useState(true);
23
- const [e2e, setE2e] = React.useState(true);
24
- const [name, setName] = React.useState("@ORGINIZATION/PROJECT");
25
-
26
- // RESULT
27
- const [document, setDocument] = React.useState<
28
- SwaggerV2.IDocument | OpenApiV3.IDocument | OpenApiV3_1.IDocument | null
29
- >(null);
30
- const [progress, setProgress] = React.useState(false);
31
-
32
- const handleError = (error: string) => {
33
- if (props.onError) props.onError(error);
34
- else alert(error);
35
- };
36
- const handleSwagger = (
37
- document:
38
- | SwaggerV2.IDocument
39
- | OpenApiV3.IDocument
40
- | OpenApiV3_1.IDocument
41
- | null,
42
- error: string | null,
43
- ) => {
44
- setDocument(document);
45
- if (error !== null) handleError(error);
46
- };
47
-
48
- const generate = async () => {
49
- if (document === null) return;
50
-
51
- setProgress(true);
52
- try {
53
- const result = await NestiaEditorComposer[mode]({
54
- document,
55
- keyword,
56
- e2e,
57
- simulate,
58
- package: name,
59
- });
60
- if (result.success === true) {
61
- StackBlitzSDK.openProject(
62
- {
63
- title: document.info?.title ?? "Nestia Editor",
64
- template: "node",
65
- files: result.data.files,
66
- },
67
- {
68
- newWindow: true,
69
- openFile: result.data.openFile,
70
- startScript: result.data.startScript as any,
71
- },
72
- );
73
- } else {
74
- handleError(JSON.stringify(result.errors, null, 2));
75
- }
76
- } catch (exp) {
77
- handleError(exp instanceof Error ? exp.message : "unknown error");
78
- }
79
- setProgress(false);
80
- };
81
-
82
- return (
83
- <>
84
- <NestiaEditorFileUploader onChange={handleSwagger} />
85
- <br />
86
- <FormControl fullWidth style={{ paddingLeft: 15 }}>
87
- <TextField
88
- onChange={(e) => setName(e.target.value)}
89
- defaultValue={name}
90
- label="Package Name"
91
- variant="outlined"
92
- />
93
- <FormLabel style={{ paddingTop: 20 }}> Mode </FormLabel>
94
- <RadioGroup
95
- defaultValue={mode}
96
- onChange={(_e, value) => setMode(value as "nest" | "sdk")}
97
- style={{ paddingLeft: 15 }}
98
- >
99
- <FormControlLabel
100
- value="sdk"
101
- control={<Radio />}
102
- label="Software Development Kit"
103
- />
104
- <FormControlLabel
105
- value="nest"
106
- control={<Radio />}
107
- label="NestJS Project"
108
- />
109
- </RadioGroup>
110
- <FormLabel style={{ paddingTop: 20 }}> Options </FormLabel>
111
- <FormControlLabel
112
- label="Keyword Parameter"
113
- style={{ paddingTop: 5, paddingLeft: 15 }}
114
- control={
115
- <Switch checked={keyword} onChange={() => setKeyword(!keyword)} />
116
- }
117
- />
118
- <FormControlLabel
119
- label="Mockup Simulator"
120
- style={{ paddingTop: 5, paddingLeft: 15 }}
121
- control={
122
- <Switch
123
- checked={simulate}
124
- onChange={() => setSimulate(!simulate)}
125
- />
126
- }
127
- />
128
- <FormControlLabel
129
- label="E2E Test Functions"
130
- style={{ paddingLeft: 15 }}
131
- control={<Switch checked={e2e} onChange={() => setE2e(!e2e)} />}
132
- />
133
- </FormControl>
134
- <br />
135
- <br />
136
- <Button
137
- component="a"
138
- fullWidth
139
- variant="contained"
140
- color={"info"}
141
- size="large"
142
- disabled={progress === true || document === null}
143
- onClick={() => generate()}
144
- >
145
- {progress ? "Generating..." : "Generate Editor"}
146
- </Button>
147
- </>
148
- );
149
- }
150
- export namespace NestiaEditorUploader {
151
- export interface IProps {
152
- onError?: (error: string) => void;
153
- }
154
- }
1
+ import {
2
+ Button,
3
+ FormControl,
4
+ FormControlLabel,
5
+ FormLabel,
6
+ Radio,
7
+ RadioGroup,
8
+ Switch,
9
+ TextField,
10
+ } from "@mui/material";
11
+ import { OpenApiV3, OpenApiV3_1, SwaggerV2 } from "@typia/interface";
12
+ import React from "react";
13
+
14
+ import { NestiaEditorArchiver } from "./internal/NestiaEditorArchiver";
15
+ import { NestiaEditorComposer } from "./internal/NestiaEditorComposer";
16
+ import { NestiaEditorFileUploader } from "./internal/NestiaEditorFileUploader";
17
+
18
+ export function NestiaEditorUploader(props: NestiaEditorUploader.IProps) {
19
+ // PARAMETERS
20
+ const [mode, setMode] = React.useState<"nest" | "sdk">("sdk");
21
+ const [keyword, setKeyword] = React.useState(true);
22
+ const [simulate, setSimulate] = React.useState(true);
23
+ const [e2e, setE2e] = React.useState(true);
24
+ const [name, setName] = React.useState("@ORGINIZATION/PROJECT");
25
+
26
+ // RESULT
27
+ const [document, setDocument] = React.useState<
28
+ SwaggerV2.IDocument | OpenApiV3.IDocument | OpenApiV3_1.IDocument | null
29
+ >(null);
30
+ const [progress, setProgress] = React.useState(false);
31
+
32
+ const handleError = (error: string) => {
33
+ if (props.onError) props.onError(error);
34
+ else alert(error);
35
+ };
36
+ const handleSwagger = (
37
+ document:
38
+ | SwaggerV2.IDocument
39
+ | OpenApiV3.IDocument
40
+ | OpenApiV3_1.IDocument
41
+ | null,
42
+ error: string | null,
43
+ ) => {
44
+ setDocument(document);
45
+ if (error !== null) handleError(error);
46
+ };
47
+
48
+ const generate = async () => {
49
+ if (document === null) return;
50
+
51
+ setProgress(true);
52
+ try {
53
+ const result = await NestiaEditorComposer[mode]({
54
+ document,
55
+ keyword,
56
+ e2e,
57
+ simulate,
58
+ package: name,
59
+ });
60
+ if (result.success === true) {
61
+ NestiaEditorArchiver.download({
62
+ name: NestiaEditorArchiver.name(name),
63
+ files: result.data.files,
64
+ });
65
+ } else {
66
+ handleError(JSON.stringify(result.errors, null, 2));
67
+ }
68
+ } catch (exp) {
69
+ handleError(exp instanceof Error ? exp.message : "unknown error");
70
+ }
71
+ setProgress(false);
72
+ };
73
+
74
+ return (
75
+ <>
76
+ <NestiaEditorFileUploader onChange={handleSwagger} />
77
+ <br />
78
+ <FormControl fullWidth style={{ paddingLeft: 15 }}>
79
+ <TextField
80
+ onChange={(e) => setName(e.target.value)}
81
+ defaultValue={name}
82
+ label="Package Name"
83
+ variant="outlined"
84
+ />
85
+ <FormLabel style={{ paddingTop: 20 }}> Mode </FormLabel>
86
+ <RadioGroup
87
+ defaultValue={mode}
88
+ onChange={(_e, value) => setMode(value as "nest" | "sdk")}
89
+ style={{ paddingLeft: 15 }}
90
+ >
91
+ <FormControlLabel
92
+ value="sdk"
93
+ control={<Radio />}
94
+ label="Software Development Kit"
95
+ />
96
+ <FormControlLabel
97
+ value="nest"
98
+ control={<Radio />}
99
+ label="NestJS Project"
100
+ />
101
+ </RadioGroup>
102
+ <FormLabel style={{ paddingTop: 20 }}> Options </FormLabel>
103
+ <FormControlLabel
104
+ label="Keyword Parameter"
105
+ style={{ paddingTop: 5, paddingLeft: 15 }}
106
+ control={
107
+ <Switch checked={keyword} onChange={() => setKeyword(!keyword)} />
108
+ }
109
+ />
110
+ <FormControlLabel
111
+ label="Mockup Simulator"
112
+ style={{ paddingTop: 5, paddingLeft: 15 }}
113
+ control={
114
+ <Switch
115
+ checked={simulate}
116
+ onChange={() => setSimulate(!simulate)}
117
+ />
118
+ }
119
+ />
120
+ <FormControlLabel
121
+ label="E2E Test Functions"
122
+ style={{ paddingLeft: 15 }}
123
+ control={<Switch checked={e2e} onChange={() => setE2e(!e2e)} />}
124
+ />
125
+ </FormControl>
126
+ <br />
127
+ <br />
128
+ <Button
129
+ component="a"
130
+ fullWidth
131
+ variant="contained"
132
+ color={"info"}
133
+ size="large"
134
+ disabled={progress === true || document === null}
135
+ onClick={() => generate()}
136
+ >
137
+ {progress ? "Generating..." : "Download Project"}
138
+ </Button>
139
+ </>
140
+ );
141
+ }
142
+ export namespace NestiaEditorUploader {
143
+ export interface IProps {
144
+ onError?: (error: string) => void;
145
+ }
146
+ }
package/src/index.ts CHANGED
@@ -1,3 +1,3 @@
1
- export * from "./NestiaEditorApplication";
2
- export * from "./NestiaEditorIframe";
3
- export * from "./NestiaEditorUploader";
1
+ export * from "./NestiaEditorApplication";
2
+ export * from "./NestiaEditorIframe";
3
+ export * from "./NestiaEditorUploader";
@@ -0,0 +1,43 @@
1
+ import { strToU8, zipSync } from "fflate";
2
+
3
+ /**
4
+ * Archives a composed project into a zip file and hands it to the browser.
5
+ *
6
+ * StackBlitz can no longer run nestia projects: the generated projects build
7
+ * through `ttsc`, whose TypeScript compiler is a native Go binary that a
8
+ * WebContainer cannot execute. The editor therefore delivers the composed
9
+ * project as a downloadable zip archive instead of an embedded StackBlitz
10
+ * workspace.
11
+ */
12
+ export namespace NestiaEditorArchiver {
13
+ /** Pack the composed project files into a zip archive. */
14
+ 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);
19
+ };
20
+
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`;
24
+
25
+ /** Trigger a browser download of the packed archive. */
26
+ export const download = (props: {
27
+ name: string;
28
+ files: Record<string, string>;
29
+ }): void => {
30
+ const blob: Blob = new Blob(
31
+ [pack(props.files) as Uint8Array<ArrayBuffer>],
32
+ {
33
+ type: "application/zip",
34
+ },
35
+ );
36
+ const url: string = URL.createObjectURL(blob);
37
+ const anchor: HTMLAnchorElement = window.document.createElement("a");
38
+ anchor.href = url;
39
+ anchor.download = props.name;
40
+ anchor.click();
41
+ setTimeout(() => URL.revokeObjectURL(url), 30_000);
42
+ };
43
+ }