Skip to content

Commit 289a774

Browse files
committed
Implemented app metadata
1 parent 9056f47 commit 289a774

File tree

9 files changed

+126
-20
lines changed

9 files changed

+126
-20
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,5 @@ yarn-error.log*
1111
*.ini
1212

1313
/tmp
14-
demo/public/config/tree.json
14+
demo/public/config/tree.json
15+
vite.config.ts.timestamp-*.mjs
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
outline: deep
3+
---
4+
5+
# @prozilla-os/app-center
6+
7+
<!--@include: ../../../../../packages/apps/app-center/README.md{13,}-->

packages/apps/app-center/src/components/header/Header.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ export function Header({ searchQuery, setSearchQuery, category, setCategory }: H
2626
<select className={styles.CategoryInput} value={category} onChange={handleCategoryChange}>
2727
<option value={"All"}>All</option>
2828
{APP_CATEGORIES.filter((category) => {
29-
return appsConfig.getAppsByCategory(category).length > 0
29+
return appsConfig.getAppsByCategory(category).length > 0;
3030
}).map((category) =>
31-
<option value={category}>{category}</option>
31+
<option key={category} value={category}>{category}</option>
3232
)}
3333
</select>
3434
</div>;

packages/core/src/features/apps/app.tsx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ import { APP_CATEGORIES } from "../../constants/apps.const";
55

66
const validIdRegex = /^[a-zA-Z0-9-]+$/;
77

8+
interface AppMetadata {
9+
name: string;
10+
version: `${number}.${number}.${number}`;
11+
author: string;
12+
}
13+
814
/**
915
* An application that can be ran by ProzillaOS
1016
* Applications can be installed by adding them to the `apps` array in {@link AppsConfig}
@@ -70,6 +76,11 @@ export class App<AppProps extends WindowProps = WindowProps> {
7076
*/
7177
category: typeof APP_CATEGORIES[number] | null = null;
7278

79+
/**
80+
* Metadata of the app's package
81+
*/
82+
metadata: AppMetadata | null = null;
83+
7384
isActive: boolean = false;
7485
isPinned?: boolean;
7586
isInstalled = true;
@@ -165,4 +176,9 @@ export class App<AppProps extends WindowProps = WindowProps> {
165176
this.category = category;
166177
return this;
167178
}
179+
180+
setMetadata(metadata: AppMetadata | null): this {
181+
this.metadata = metadata;
182+
return this;
183+
}
168184
}

packages/dev-tools/src/configs/app.vite.config.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import react from "@vitejs/plugin-react-swc";
33
import dts from "vite-plugin-dts";
44
import cssInjectedByJs from "vite-plugin-css-injected-by-js";
55
import { posix, resolve, sep } from "path";
6+
import { appMetadataPlugin } from "../plugins";
67

78
/**
89
* Helper function for creating Vite configurations for ProzillaOS apps
@@ -23,15 +24,18 @@ export const appViteConfig = (basePath: string, entryPath: string): UserConfig =
2324

2425
return {
2526
plugins: [
27+
appMetadataPlugin({
28+
entryPath,
29+
}),
2630
react(),
2731
cssInjectedByJs(),
2832
dts({
2933
outDir: "dist",
3034
rollupTypes: true,
3135
strictOutput: true,
3236
pathsToAliases: false,
33-
tsconfigPath: "tsconfig.build.json"
34-
})
37+
tsconfigPath: "tsconfig.build.json",
38+
}),
3539
],
3640
build: {
3741
lib: {
@@ -41,11 +45,12 @@ export const appViteConfig = (basePath: string, entryPath: string): UserConfig =
4145
rollupOptions: {
4246
external: ["react", "react/jsx-runtime", "@prozilla-os/core", "@prozilla-os/shared", /@fortawesome\/*/g],
4347
output: {
44-
assetFileNames: "chunks/[name][extname]",
48+
assetFileNames: "assets/[name][extname]",
49+
chunkFileNames: "chunks/[name]-[hash].js",
4550
entryFileNames: "[name].js",
46-
}
51+
},
4752
},
48-
sourcemap: true
49-
}
53+
sourcemap: true,
54+
},
5055
};
5156
};
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import { readFileSync } from "fs";
2+
import { resolve } from "path";
3+
import { RollupError } from "rollup";
4+
import { Plugin } from "vite";
5+
6+
interface PackageJson {
7+
name: string;
8+
version: string;
9+
author?: string | { name: string };
10+
}
11+
12+
interface AppMetadataPluginOptions {
13+
entryPath: string;
14+
}
15+
16+
export function appMetadataPlugin({ entryPath }: AppMetadataPluginOptions): Plugin {
17+
return {
18+
name: "vite-plugin-app-metadata",
19+
apply: "build",
20+
load(id) {
21+
if (!id.includes(entryPath)) return null;
22+
23+
const rootDir = process.cwd();
24+
const packageJsonPath = resolve(rootDir, "package.json");
25+
26+
// Read and parse the package.json file
27+
let packageJson: PackageJson | null = null;
28+
try {
29+
const packageJsonContent = readFileSync(packageJsonPath, "utf-8");
30+
packageJson = JSON.parse(packageJsonContent) as PackageJson;
31+
} catch (error) {
32+
this.error(error as RollupError);
33+
}
34+
35+
if (!packageJson)
36+
return null;
37+
38+
const { name, version } = packageJson;
39+
let { author = "Unknown" } = packageJson;
40+
41+
if (typeof author == "string") {
42+
author = author.replace(/<[^>]*>|\([^)]*\)/g, "").trim();
43+
} else {
44+
author = author.name;
45+
}
46+
47+
// Read the source file content
48+
let code: string | null = null;
49+
try {
50+
code = readFileSync(id, "utf-8");
51+
} catch (error) {
52+
this.error(error as RollupError);
53+
}
54+
55+
if (code == null)
56+
return null;
57+
58+
// Find instance of app class
59+
const appInstanceRegex = /const\s+(\w+)\s*=\s*new\s+App(?:<[\w\s,]+>)?\s*\(([^;]*)\)\s*(\.[\w]+\([^)]*\)\s*)*;/;
60+
const match = code.match(appInstanceRegex);
61+
62+
if (match) {
63+
const appInstanceName = match[1];
64+
65+
// Inject code to set metadata of app
66+
const injectCode = `\n${appInstanceName}.setMetadata({ name: "${name}", version: "${version}", author: "${author}" });\n`;
67+
const modifiedCode = code.replace(appInstanceRegex, match[0] + injectCode);
68+
69+
return modifiedCode;
70+
} else {
71+
this.warn("No App instance found in the entry file.");
72+
return null;
73+
}
74+
},
75+
};
76+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
export { stageSitePlugin } from "./stageSite";
2+
export { appMetadataPlugin } from "./appMetadata";
23

34
export type { StageOptions } from "./stageSite";

packages/dev-tools/src/plugins/stageSite.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ function generate404Page(context: PluginContext, template: string) {
127127
context.emitFile({
128128
type: "asset",
129129
fileName: "404.html",
130-
source: template
130+
source: template,
131131
});
132132
}
133133

@@ -164,7 +164,7 @@ function generateAppPages(context: PluginContext, template: string, options: Sta
164164
context.emitFile({
165165
type: "asset",
166166
fileName: `${appId}.html`,
167-
source: html
167+
source: html,
168168
});
169169
}
170170
}
@@ -195,14 +195,14 @@ function stageSite(context: PluginContext, bundle: OutputBundle, { appsConfig, s
195195
domain,
196196
baseUrl,
197197
imageUrls,
198-
paths
198+
paths,
199199
};
200200

201201
files.forEach(([path, generateContent]) => {
202202
context.emitFile({
203203
type: "asset",
204204
fileName: path,
205-
source: generateContent(extendedOptions)
205+
source: generateContent(extendedOptions),
206206
});
207207
});
208208

@@ -213,7 +213,7 @@ function stageSite(context: PluginContext, bundle: OutputBundle, { appsConfig, s
213213
context.emitFile({
214214
type: "asset",
215215
fileName: "index.html",
216-
source: template
216+
source: template,
217217
});
218218

219219
generate404Page(context, template);

packages/dev-tools/vite.config.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,22 @@ export default defineConfig({
1212
strictOutput: true,
1313
pathsToAliases: false,
1414
bundledPackages: ["@prozilla-os/*"],
15-
tsconfigPath: "tsconfig.build.json"
16-
})
15+
tsconfigPath: "tsconfig.build.json",
16+
}),
1717
],
1818
build: {
1919
lib: {
2020
entry: resolve(__dirname, "src/main.ts"),
2121
formats: ["es"],
2222
},
2323
rollupOptions: {
24-
external: ["vite", "path", /vite-plugin-/g, /@vitejs\/plugin-/g, "rollup", "@prozilla-os/core", "@prozilla-os/shared"],
24+
external: ["vite", "path", "fs", "typescript", /vite-plugin-/g, /@vitejs\/plugin-/g, "rollup", "@prozilla-os/core", "@prozilla-os/shared"],
2525
output: {
2626
assetFileNames: "assets/[name][extname]",
2727
chunkFileNames: "chunks/[name]-[hash].js",
2828
entryFileNames: "[name].js",
29-
}
29+
},
3030
},
31-
sourcemap: true
32-
}
31+
sourcemap: true,
32+
},
3333
});

0 commit comments

Comments
 (0)