create-outsystems-astro 0.1.0 → 0.3.0

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/README.md CHANGED
@@ -2,9 +2,9 @@
2
2
  Generates [Astro Islands](https://docs.astro.build/en/concepts/islands/) for use in OutSystems that can create self contained interactive code elements from different frameworks. It allows an extension of the front-end with these dynamic libraries.
3
3
 
4
4
  ## When to use this library
5
- - Custom interactive elements that would not be difficult/not possible to build directly in OutSystems.
5
+ - Custom interactive elements that would be difficult/not possible to build directly in OutSystems.
6
6
  - Wrappers around interactive elements built in other front-end frameworks.
7
- - Direct migration of traditional code.
7
+ - Direct migration of external traditional code.
8
8
 
9
9
  ## When NOT to use this library
10
10
  - You will most likely not need to use this library for most of the front-end development. This is similar in use to the custom code development in for the back-end in [O11](https://success.outsystems.com/documentation/11/integration_with_external_systems/extend_logic_with_your_own_code/) and [ODC](https://success.outsystems.com/documentation/outsystems_developer_cloud/building_apps/extend_your_apps_with_custom_code/).
@@ -12,13 +12,38 @@ Generates [Astro Islands](https://docs.astro.build/en/concepts/islands/) for use
12
12
  - Loading performance of component must be instant. The Astro Island will load after the page/screen has loaded since the initializer and tag will be loaded after.
13
13
 
14
14
  ## Current supported frameworks
15
- - [React](https://docs.astro.build/en/guides/integrations-guide/react/).
15
+ - [React](https://docs.astro.build/en/guides/integrations-guide/react/)
16
+ - [Vue](https://docs.astro.build/en/guides/integrations-guide/vue/)
16
17
 
17
18
  ## Getting started
18
19
  Run the Create OutSystems Astro generator:
20
+
21
+ ### npm
19
22
  ```bash
20
23
  npx create-outsystems-astro
21
24
  ```
25
+
26
+ ### Yarn
27
+ ```bash
28
+ yarn create outsystems-astro
29
+ ```
30
+
31
+ ### pnpm
32
+ ```bash
33
+ pnpm dlx create-outsystems-astro
34
+ ```
35
+
36
+ ### Bun
37
+ ```bash
38
+ bunx create-outsystems-astro
39
+ ```
40
+
41
+ ### Deno
42
+ The Deno DX command is available in [Deno 2.6](https://deno.com/blog/v2.6).
43
+ ```bash
44
+ dx create-outsystems-astro
45
+ ```
46
+
22
47
  This will create the generated files as well as an example component.
23
48
 
24
49
  ## 🚀 Project Structure
@@ -54,6 +79,8 @@ Stylesheets that may apply to the component.
54
79
 
55
80
  All commands are run from the root of the project, from a terminal:
56
81
 
82
+ ### npm
83
+
57
84
  | Command | Action |
58
85
  | :------------------------ | :----------------------------------------------- |
59
86
  | `npm install` | Installs dependencies |
@@ -64,12 +91,84 @@ All commands are run from the root of the project, from a terminal:
64
91
  | `npm run astro ...` | Run CLI commands like `astro add`, `astro check` |
65
92
  | `npm run astro -- --help` | Get help using the Astro CLI |
66
93
 
94
+ ### Yarn
95
+
96
+ | Command | Action |
97
+ | :------------------------ | :----------------------------------------------- |
98
+ | `yarn install` | Installs dependencies |
99
+ | `yarn run dev` | Starts local dev server at `localhost:4321` |
100
+ | `yarn run build` | Build distribution to `./dist/` |
101
+ | `yarn run output` | Build OutSystems production site to `./output/` |
102
+ | `yarn run preview` | Preview build locally, before creating output |
103
+ | `yarn run astro ...` | Run CLI commands like `astro add`, `astro check` |
104
+ | `yarn run astro -- --help` | Get help using the Astro CLI |
105
+
106
+ ### pnpm
107
+
108
+ | Command | Action |
109
+ | :------------------------ | :----------------------------------------------- |
110
+ | `pnpm install` | Installs dependencies |
111
+ | `pnpm run dev` | Starts local dev server at `localhost:4321` |
112
+ | `pnpm run build` | Build distribution to `./dist/` |
113
+ | `pnpm run output` | Build OutSystems production site to `./output/` |
114
+ | `pnpm run preview` | Preview build locally, before creating output |
115
+ | `pnpm run astro ...` | Run CLI commands like `astro add`, `astro check` |
116
+ | `pnpm run astro -- --help` | Get help using the Astro CLI |
117
+
118
+ ### Bun
119
+
120
+ | Command | Action |
121
+ | :------------------------ | :----------------------------------------------- |
122
+ | `bun install` | Installs dependencies |
123
+ | `bun run dev` | Starts local dev server at `localhost:4321` |
124
+ | `bun run build` | Build distribution to `./dist/` |
125
+ | `bun run output` | Build OutSystems production site to `./output/` |
126
+ | `bun run preview` | Preview build locally, before creating output |
127
+ | `bun run astro ...` | Run CLI commands like `astro add`, `astro check` |
128
+ | `bun run astro -- --help` | Get help using the Astro CLI |
129
+
130
+ ### Deno
131
+
132
+ | Command | Action |
133
+ | :------------------------ | :----------------------------------------------- |
134
+ | `deno install` | Installs dependencies |
135
+ | `deno run dev` | Starts local dev server at `localhost:4321` |
136
+ | `deno run build` | Build distribution to `./dist/` |
137
+ | `deno run output` | Build OutSystems production site to `./output/` |
138
+ | `deno run preview` | Preview build locally, before creating output |
139
+ | `deno run astro ...` | Run CLI commands like `astro add`, `astro check` |
140
+ | `deno run astro -- --help` | Get help using the Astro CLI |
141
+
142
+ ## Getting Started
143
+ Delete the demo application under the ```src``` folder and being to build your own application.
67
144
 
68
145
  ## Converting to OutSystems
69
146
 
70
- Once development is complete, run:
147
+ Once development is complete, run the output generation command:
148
+
149
+ ### npm
71
150
  ```bash
72
151
  npm run output
73
152
  ```
74
153
 
154
+ ### Yarn
155
+ ```bash
156
+ yarn run output
157
+ ```
158
+
159
+ ### pnpm
160
+ ```bash
161
+ pnpm run output
162
+ ```
163
+
164
+ ### Bun
165
+ ```bash
166
+ bun run output
167
+ ```
168
+
169
+ ### Deno
170
+ ```bash
171
+ deno run output
172
+ ```
173
+
75
174
  This will create a set of files that will then need to be coverted to OutSystems components.
package/bin/cli.js CHANGED
@@ -8,6 +8,19 @@ import { execSync } from "child_process";
8
8
  const __filename = fileURLToPath(import.meta.url);
9
9
  const __dirname = path.dirname(__filename);
10
10
 
11
+ const FRAMEWORKS = [
12
+ { title: "React", value: "react" },
13
+ { title: "Vue", value: "vue" }
14
+ ];
15
+
16
+ const LOCKFILES = {
17
+ npm: ["package-lock.json"],
18
+ yarn: ["yarn.lock"],
19
+ pnpm: ["pnpm-lock.yaml"],
20
+ bun: ["bun.lock"],
21
+ deno: ["deno.lock"]
22
+ };
23
+
11
24
  async function main() {
12
25
  console.log("🚀 Welcome to create-outsystems-astro!");
13
26
 
@@ -26,6 +39,28 @@ async function main() {
26
39
  console.log("📦 Copying template...");
27
40
  copyDir(templateDir, targetDir);
28
41
 
42
+ const packageManager = packageInstall(targetDir);
43
+
44
+ let selectedFrameworks = [];
45
+
46
+ while (selectedFrameworks.length === 0) {
47
+ const frameworkResponse = await prompts({
48
+ type: "multiselect",
49
+ name: "frameworks",
50
+ message: "Which frameworks do you want to include?",
51
+ choices: FRAMEWORKS,
52
+ hint: "- Space to select. Enter to confirm",
53
+ validate: value =>
54
+ value.length > 0 ? true : "Please select at least one framework."
55
+ });
56
+
57
+ selectedFrameworks = frameworkResponse.frameworks || [];
58
+ }
59
+
60
+ deleteUnselectedFrameworkFolders(targetDir, selectedFrameworks);
61
+
62
+ updateAstroConfig(targetDir, selectedFrameworks);
63
+
29
64
  const readmeSrc = path.resolve(__dirname, "../README.md");
30
65
  const readmeDest = path.join(targetDir, "README.md");
31
66
 
@@ -33,20 +68,14 @@ async function main() {
33
68
  fs.copyFileSync(readmeSrc, readmeDest);
34
69
  }
35
70
 
36
- // Install dependencies
37
- console.log("📦 Installing dependencies...");
38
- try {
39
- execSync("npm install", { cwd: targetDir, stdio: "inherit" });
40
- } catch {
41
- console.warn("⚠️ Failed to automatically install dependencies.");
42
- }
71
+
43
72
 
44
73
  console.log(`
45
74
  ✅ All done!
46
75
 
47
76
  Next steps:
48
77
  cd ${response.projectName}
49
- npm run dev
78
+ ${packageManager} run dev
50
79
  `);
51
80
  }
52
81
 
@@ -65,6 +94,130 @@ function copyDir(src, dest) {
65
94
  }
66
95
  }
67
96
 
97
+ function deleteUnselectedFrameworkFolders(projectDir, selectedFrameworks) {
98
+ const allFrameworks = FRAMEWORKS.map(f => f.value);
99
+
100
+ const frameworksToDelete = allFrameworks.filter(
101
+ f => !selectedFrameworks.includes(f)
102
+ );
103
+
104
+ for (const framework of frameworksToDelete) {
105
+ const pageDir = path.join(projectDir, "src", "pages", framework);
106
+ const componentDir = path.join(projectDir, "src", "framework", framework);
107
+
108
+ if (fs.existsSync(pageDir)) {
109
+ console.log(`🗑️ Removing ${path.relative(projectDir, pageDir)}`);
110
+ fs.rmSync(pageDir, { recursive: true, force: true });
111
+ }
112
+
113
+ if (fs.existsSync(componentDir)) {
114
+ console.log(`🗑️ Removing ${path.relative(projectDir, componentDir)}`);
115
+ fs.rmSync(componentDir, { recursive: true, force: true });
116
+ }
117
+ }
118
+ }
119
+
120
+ function updateAstroConfig(projectDir, selectedFrameworks) {
121
+ const configPath = path.join(projectDir, "astro.config.mjs");
122
+
123
+ if (!fs.existsSync(configPath)) {
124
+ console.warn("⚠️ astro.config.mjs not found, skipping integration cleanup.");
125
+ return;
126
+ }
127
+
128
+ let content = fs.readFileSync(configPath, "utf-8");
129
+
130
+ const allFrameworks = {
131
+ react: {
132
+ import: /import\s+react\s+from\s+['"]@astrojs\/react['"];\s*\n?/,
133
+ integration: /react\(\)\s*,?\s*/
134
+ },
135
+ vue: {
136
+ import: /import\s+vue\s+from\s+['"]@astrojs\/vue['"];\s*\n?/,
137
+ integration: /vue\(\)\s*,?\s*/
138
+ }
139
+ };
140
+
141
+ for (const [framework, patterns] of Object.entries(allFrameworks)) {
142
+ if (!selectedFrameworks.includes(framework)) {
143
+ content = content.replace(patterns.import, "");
144
+ content = content.replace(patterns.integration, "");
145
+ }
146
+ }
147
+
148
+ // Clean up trailing commas inside integrations array
149
+ content = content.replace(
150
+ /integrations:\s*\[\s*,/g,
151
+ "integrations: ["
152
+ );
153
+ content = content.replace(
154
+ /,\s*\]/g,
155
+ "]"
156
+ );
157
+
158
+ fs.writeFileSync(configPath, content, "utf-8");
159
+ console.log("🛠️ Updated astro.config.mjs integrations");
160
+ }
161
+
162
+ function detectPackageManager() {
163
+ if (typeof Deno !== "undefined") return "deno";
164
+
165
+ const ua = process.env.npm_config_user_agent || "";
166
+
167
+ if (ua.startsWith("npm/")) return "npm";
168
+ if (ua.startsWith("yarn/")) return "yarn";
169
+ if (ua.startsWith("pnpm/")) return "pnpm";
170
+ if (ua.startsWith("bun/")) return "bun";
171
+
172
+ return "unknown";
173
+ }
174
+
175
+ function cleanupLockfiles(projectDir, activePackageManager) {
176
+ for (const [packageManager, files] of Object.entries(LOCKFILES)) {
177
+ if (packageManager === activePackageManager) continue;
178
+
179
+ for (const file of files) {
180
+ const filePath = path.join(projectDir, file);
181
+ if (fs.existsSync(filePath)) {
182
+ fs.rmSync(filePath, { force: true });
183
+ console.log(`🗑️ Removed ${file}`);
184
+ }
185
+ }
186
+ }
187
+ }
188
+
189
+ function packageInstall(targetDir) {
190
+ try {
191
+ const packageManager = detectPackageManager();
192
+ console.log(`🧰 Detected package manager: ${packageManager}`);
193
+
194
+ if (packageManager === "unknown") {
195
+ console.warn("⚠️ Could not detect package manager — keeping all lockfiles.");
196
+ } else {
197
+ cleanupLockfiles(targetDir, packageManager);
198
+ }
199
+
200
+ const installCmd = {
201
+ npm: "npm install",
202
+ yarn: "yarn",
203
+ pnpm: "pnpm install",
204
+ bun: "bun install",
205
+ deno: "deno install",
206
+ unknown: "npm install"
207
+ }[packageManager];
208
+
209
+ console.log(`📦 Installing dependencies using ${packageManager}...`);
210
+ execSync(installCmd, {
211
+ cwd: targetDir,
212
+ stdio: "inherit"
213
+ });
214
+
215
+ return packageManager
216
+ } catch {
217
+ console.warn("⚠️ Failed to automatically install dependencies.");
218
+ }
219
+ }
220
+
68
221
  main().catch(err => {
69
222
  console.error(err);
70
223
  process.exit(1);
package/package.json CHANGED
@@ -1,14 +1,15 @@
1
1
  {
2
2
  "name": "create-outsystems-astro",
3
3
  "type": "module",
4
- "version": "0.1.0",
4
+ "version": "0.3.0",
5
5
  "description": "Create an OutSystems Astro Island project to import as a component into your OutSystems application",
6
6
  "bin": {
7
7
  "create-outsystems-astro": "bin/cli.js"
8
8
  },
9
9
  "files": [
10
10
  "bin",
11
- "template"
11
+ "template",
12
+ "template/.gitignore"
12
13
  ],
13
14
  "publishConfig": {
14
15
  "access": "public"
@@ -0,0 +1,6 @@
1
+ # Copilot instructions
2
+
3
+ This file is the authoritative Copilot instruction file for this repository.
4
+ If any content in AGENTS.md conflicts with the instructions below, always follow the instructions in this file.
5
+
6
+ Reference (for additional details): [AGENTS.md](../AGENTS.md)
@@ -0,0 +1,27 @@
1
+ # build output
2
+ dist/
3
+ # generated types
4
+ .astro/
5
+
6
+ # dependencies
7
+ node_modules/
8
+
9
+ # logs
10
+ npm-debug.log*
11
+ yarn-debug.log*
12
+ yarn-error.log*
13
+ pnpm-debug.log*
14
+
15
+
16
+ # environment variables
17
+ .env
18
+ .env.production
19
+
20
+ # macOS-specific files
21
+ .DS_Store
22
+
23
+ # jetbrains setting folder
24
+ .idea/
25
+
26
+ # output folder
27
+ output/
@@ -0,0 +1,107 @@
1
+ # OutSystems Astro Islands Development Instructions
2
+
3
+ ## Project Context
4
+ - This is not an Astro project that will be deployed on its own. It is only used for the output generation.
5
+ - The output generation will be only client side. No server side rendering or server side components will be used.
6
+ - The Astro Islands can be used generated with the following frameworks:
7
+ - React
8
+ - Vue
9
+ - Prefer to use TypeScript when possible.
10
+
11
+ ## OutSystems
12
+ - This project works for OutSystems 11 (O11) Reactive and OutSystems Developer Cloud (ODC). It does not work with OutSystems 11 Traditional projects.
13
+ - The documentation for importing a component into OutSystems 11 is availabe at https://hs2323.github.io/create-outsystems-astro/guides/outsystems/o11/.
14
+ - The documentation for importing a component into OutSystems 11 is availabe at https://hs2323.github.io/create-outsystems-astro/guides/outsystems/o11/.
15
+
16
+ ## Development
17
+
18
+ ### Starting project
19
+ - The project can intialized from the Create OutSystems Astro package (https://www.npmjs.com/package/create-outsystems-astro).
20
+ - In this document, for any reference to running package manager script, the ```PM``` attribute should be replaced with whatever package manager the user is using.
21
+
22
+ ### Pages
23
+ - The files in src/pages/*.astro are used as a starting point and holds the components for generation. They can be tested by running ```npm run dev```. That will show what the component looks like as rendered. The sample example pages are broken out by framework name (src/pages/react, src/pages/vue, etc). This page will house the component(s) entry points.
24
+ - When importing a component, the component must have the attribute of the client:only= + the framework name.
25
+ - React: ```client:only="react"```.
26
+ - Vue: ```client:only="vue"```.
27
+
28
+ ### Components
29
+ - The components live in the folder framework/[NAME]/ (src/framework/react, src/framework/vue, etc)) with each framework having its own folder. This is recommended but can be renamed to something else.
30
+
31
+ ### Parameters
32
+ - Parameters are assigned as attributes on the component. Each framework will then handle them as incoming parameters.
33
+ - OutSystems will pass in parameters already prepared for the ````<astro-island>```. It already has copied the Astro method of serialization in https://github.com/withastro/astro/blob/main/packages/astro/src/runtime/server/serialize.ts.
34
+
35
+ #### Slots
36
+ Astro slots can be sent in. A slot can be either the default one or the named one. Each framework handles slots differently. Slots can only be HTML elements and cannot be components of a framework.
37
+
38
+ ##### React
39
+ - In React, slots are handled as props. The default slot is the ```children``` prop. A named slot will have the name of its slot as the parameter. For example, a slot with the following:
40
+ ```js
41
+ <div slot="header">
42
+ ```
43
+ will have the parameter named header.
44
+ - The slots are then rendered using the regular React rendering parameter method. With the following Astro component:
45
+ ```js
46
+ ---
47
+ import CounterComponent from '../../framework/react/Counter';
48
+ ---
49
+ <CounterComponent client:only="react">
50
+ <div slot="header">
51
+ Counter
52
+ </div>
53
+ <div style="text-align: center;">
54
+ <p>Slot content!</p>
55
+ </div>
56
+ </CounterComponent>
57
+ ```
58
+ the slots will render as:
59
+ ```js
60
+ export default function Counter({
61
+ children,
62
+ header,
63
+ }: {
64
+ children: React.ReactNode;
65
+ header: React.ReactNode;
66
+ }) {
67
+
68
+ return (
69
+ <>
70
+ {header}
71
+ <div>
72
+ {children}
73
+ </div>
74
+ </>
75
+ );
76
+ }
77
+
78
+ ```
79
+
80
+ ##### Vue
81
+ - In Vue, slots are handled as by using the <slot /> tag. The default slot is the is just <slot />. A named slot will have the name of its slot as an attribute such as <slot name="header" />. Placement of the slot will determine where the slot will render.
82
+
83
+ ### Testing
84
+ - No testing is built into this generator. It is recommended to use best practices for each framework. For example, in React, use Vitest for unit testing, React Testing Library for integration testing of components and PlayWright for end-to-end testing.
85
+
86
+ ### Linting and formatting
87
+ - No linting or formatting is built into this generator. It is recommended to add Prettier for formatting and ESLint for linting.
88
+
89
+ ### TypeScript
90
+ - If using TypeScript, it is recommended to do a TypeScript check.
91
+
92
+ ### Handlers
93
+ - Incoming functions from OutSystems cannot be passed as function handlers. The way that OutSystems will invoke them is by binding the function with the name to the ```document``` object of the page. Then it will pass in that name as a parameter. For example, if you need a function handler of ```ShowMessage```, it will need to be called as ```document[ShowMessage]```.
94
+ - Passing in basic text, number and boolean should be fine to the handler. Any array or object must be JSON stringified prior to being passed into the handler.
95
+
96
+ ## Generating output
97
+ - The ```.env.template``` must be copied over to ```.env```.
98
+ - The name of the module/library/application where the component will live must be set in the ```ASSET_URL``` variable of the ```.env``` file.
99
+ - Run the command ```PM run output```. This will run the Astro build and then run an additional step to generate the output necessary for importing into OutSystems.
100
+ - The output will be in the output/ folder. The contents are:
101
+ - HTML file(s) *.html:
102
+ - This will contain only the ```<astro-island>``` component. It will be necessary for the users to copy over the ```component-url```, ```renderer-url``` and ```opts```. The rest will either be custom built in OutSystems or not needed. The ```uid``` will be generated by OutSystems. The ```component-export```, ```client```, ```ssr``` and ```await-children``` will be automatically added in the OutSystems Islands module.
103
+ - The slot content will be converted and parsed in a way that can be then dropped in as text directly into the OutSystem parameter.
104
+ - JavaScript files *.js:
105
+ - The JavaScript files will be imported as resources and then mapped as parameters when importing the Islands module.
106
+ - Asset files:
107
+ The ```/assets``` folder may contain images, stylesheets and other assets. For images, they should be copied in as resources into the module/library/component/application. Any CSS must be manually copied from the ```.css``` files and manually imported into the project or the block level CSS.
@@ -0,0 +1,7 @@
1
+ # CLAUDE.md
2
+
3
+ ## Relationship to AGENTS.md
4
+
5
+ This document extends and specializes the general agent behaviors defined in [AGENTS.md](./AGENTS.md).
6
+
7
+ **Precedence Rule**: When there are conflicts or overlapping guidance between these documents, **CLAUDE.md takes precedence** for all interactions with Claude models. AGENTS.md provides the foundational agent patterns, while this document contains Claude-specific overrides and optimizations.
@@ -0,0 +1,12 @@
1
+ # GEMINI.md
2
+
3
+ ## Relationship to AGENTS.md
4
+
5
+ This document extends and specializes the general agent behaviors defined in [AGENTS.md](./AGENTS.md).
6
+
7
+ **Precedence Rule**: When there are conflicts or overlapping guidance between these documents, **GEMINI.md takes precedence** for all interactions with Gemini models. AGENTS.md provides the foundational agent patterns, while this document contains Gemini-specific overrides and optimizations.
8
+
9
+ ---
10
+
11
+ ## Imported Context
12
+ @./AGENTS.md
@@ -1,11 +1,11 @@
1
1
  // @ts-check
2
2
  import react from '@astrojs/react';
3
+ import vue from '@astrojs/vue';
3
4
  import { defineConfig } from 'astro/config';
4
5
 
5
-
6
6
  // https://astro.build/config
7
7
  export default defineConfig({
8
- integrations: [react()],
8
+ integrations: [react(), vue()],
9
9
  build: {
10
10
  inlineStylesheets: 'always'
11
11
  },
@@ -26,4 +26,4 @@ export default defineConfig({
26
26
  },
27
27
  },
28
28
  },
29
- });
29
+ });