Skip to content

Commit a076bd8

Browse files
authored
More stuffs (#117)
* Start of an Angular platform adapter * Adding a discovery module which can run against the local FS or the Github API * Use discovery on build * Mocha tests
1 parent b91c223 commit a076bd8

File tree

28 files changed

+4680
-889
lines changed

28 files changed

+4680
-889
lines changed

package-lock.json

Lines changed: 3916 additions & 773 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,17 @@
1212
"packages/**/*"
1313
],
1414
"devDependencies": {
15+
"@types/mocha": "*",
1516
"@typescript-eslint/eslint-plugin": "^6.10.0",
1617
"eslint": "^8.53.0",
1718
"eslint-config-google": "^0.14.0",
1819
"eslint-config-prettier": "^9.0.0",
1920
"eslint-plugin-jsdoc": "^46.8.2",
2021
"eslint-plugin-prettier": "^5.0.1",
2122
"lerna": "^7.4.0",
23+
"mocha": "^10.2.0",
2224
"prettier": "^3.0.3",
25+
"ts-mocha": "^10.0.0",
2326
"typescript": "^5.2.0"
2427
}
2528
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/e2e
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
{
2+
"name": "@apphosting/adapter-angular",
3+
"version": "17.0.0",
4+
"main": "dist/index.js",
5+
"description": "Experimental addon to the Firebase CLI to add web framework support",
6+
"repository": {
7+
"type": "git",
8+
"url": "git+https://github.com/FirebaseExtended/firebase-framework-tools.git"
9+
},
10+
"bin": {
11+
"apphosting-adapter-angular-build": "dist/bin/build.js",
12+
"apphosting-adapter-angular-create": "dist/bin/create.js"
13+
},
14+
"author": {
15+
"name": "Firebase",
16+
"url": "https://firebase.google.com/"
17+
},
18+
"bugs": {
19+
"url": "https://github.com/FirebaseExtended/firebase-framework-tools/issues"
20+
},
21+
"type": "module",
22+
"sideEffects": false,
23+
"scripts": {
24+
"build": "rm -rf dist && tsc && chmod +x ./dist/bin/*",
25+
"test": "ts-mocha -p tsconfig.json src/**/*.spec.ts"
26+
},
27+
"exports": {
28+
".": {
29+
"node": "./dist/index.js",
30+
"default": null
31+
},
32+
"./dist/*": {
33+
"node": "./dist/*",
34+
"default": null
35+
}
36+
},
37+
"files": [
38+
"dist"
39+
],
40+
"license": "Apache-2.0",
41+
"dependencies": {
42+
"fs-extra": "*",
43+
"yaml": "*",
44+
"tslib": "*",
45+
"@npmcli/run-script": "*"
46+
},
47+
"peerDependencies": {
48+
"@angular-devkit/architect": "~0.1700.0",
49+
"@angular-devkit/core": "~17.0.0"
50+
},
51+
"peerDependenciesMeta": {
52+
"@angular-devkit/architect": { "optional": true },
53+
"@angular-devkit/core": { "optional": true }
54+
},
55+
"devDependencies": {
56+
"@angular-devkit/architect": "~0.1700.0",
57+
"@angular-devkit/core": "~17.0.0",
58+
"@angular/core": "~17.0.0",
59+
"@types/fs-extra": "*",
60+
"@types/mocha": "*",
61+
"@types/tmp": "*",
62+
"semver": "*",
63+
"tmp": "*",
64+
"ts-node": "*",
65+
"mocha": "*",
66+
"ts-mocha": "*",
67+
"typescript": "*"
68+
}
69+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#! /usr/bin/env node
2+
import { spawn } from "child_process";
3+
import { loadConfig } from "../utils.js";
4+
5+
const build = (cwd = process.cwd()) =>
6+
new Promise<void>((resolve, reject) => {
7+
// TODO warn if the build script contains anything other than `ng build`
8+
const process = spawn("npm", ["run", "build"], { cwd, shell: true, stdio: "pipe" });
9+
process.stdout.on("data", (it: Buffer) => console.log(it.toString().trim()));
10+
process.stderr.on("data", (it: Buffer) => console.error(it.toString().trim()));
11+
process.on("exit", (code) => {
12+
if (code === 0) return resolve();
13+
reject();
14+
});
15+
});
16+
17+
const config = await loadConfig(process.cwd());
18+
19+
await build().catch(() => process.exit(1));
20+
21+
// TODO do all the things
22+
console.log({ config });
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import assert from "assert";
2+
import { parse } from "semver";
3+
import fsExtra from "fs-extra";
4+
5+
const { readJson } = fsExtra;
6+
7+
const readPackageJson = readJson("package.json");
8+
const importCreateJs = import("@apphosting/adapter-angular/dist/bin/create.js");
9+
10+
describe("peer dependencies", async () => {
11+
12+
let expectedAngularRange: string;
13+
let exepctedDevKitArchitectRange: string;
14+
15+
before(async () => {
16+
const packageJson = await readPackageJson;
17+
const version = parse(packageJson.version);
18+
if (!version) throw "couldn't parse package.json version";
19+
expectedAngularRange = `~${version.major}.${version.minor}.0`;
20+
exepctedDevKitArchitectRange = `~0.${version.major}${version.minor < 10 ? '0' : ''}${version.minor}.0`;
21+
});
22+
23+
it("expected @angular/cli version requirement to match", async () => {
24+
const { ANGULAR_CLI_VERSION } = await importCreateJs;
25+
assert.equal(expectedAngularRange, ANGULAR_CLI_VERSION);
26+
});
27+
28+
it("expected @angular-devkit/architect version requirement to match", async () => {
29+
const packageJson = await readPackageJson;
30+
const devKitArchitectRange = packageJson.peerDependencies["@angular-devkit/architect"];
31+
assert.equal(exepctedDevKitArchitectRange, devKitArchitectRange);
32+
});
33+
34+
it("expected @angular-devkit/core version requirement to match", async () => {
35+
const packageJson = await readPackageJson;
36+
const devKitCoreRange = packageJson.peerDependencies["@angular-devkit/core"];
37+
assert.equal(expectedAngularRange, devKitCoreRange);
38+
});
39+
});
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
#! /usr/bin/env node
2+
import { spawn } from "child_process";
3+
4+
import { isMain } from "../utils.js";
5+
6+
export const ANGULAR_CLI_VERSION = "~17.0.0";
7+
8+
const main = isMain(import.meta);
9+
10+
// TODO can we write a test to see if we're capturing all options from --help?
11+
const enum Options {
12+
help = "--help",
13+
interactive = "--interactive",
14+
dryRun = "--dry-run",
15+
defaults = "--defaults",
16+
force = "--force",
17+
collection = "--collection",
18+
commit = "--commit",
19+
createApplication = "--create-application",
20+
directory = "--directory",
21+
inlineStyle = "--inline-style",
22+
inlineTemplate = "--inline-template",
23+
minimal = "--minimal",
24+
newProjecRoot = "--new-project-root",
25+
packageManager = "--package-manager",
26+
prefix = "--prefix",
27+
routing = "--routing",
28+
skipGit = "--skip-git",
29+
skipInstall = "--skip-install",
30+
skipTests = "--skip-tests",
31+
ssr = "--ssr",
32+
standalone = "--standalone",
33+
strict = "--strict",
34+
style = "--style",
35+
viewEncapsulation = "--view-encapsulation",
36+
}
37+
38+
export async function create(projectDirectory = process.argv[2], cwd = process.cwd()) {
39+
return await new Promise<void>((resolve, reject) => {
40+
const args = [
41+
"-y",
42+
"-p",
43+
`@angular/cli@${ANGULAR_CLI_VERSION}`,
44+
"ng",
45+
"new",
46+
"hello-world",
47+
Options.directory,
48+
projectDirectory,
49+
Options.skipGit,
50+
];
51+
const process = spawn("npx", args, { cwd, shell: true, stdio: "inherit" });
52+
process.on("exit", (code) => {
53+
if (code === 0) return resolve();
54+
reject();
55+
});
56+
});
57+
}
58+
59+
if (main) {
60+
await create().catch(() => process.exit(1));
61+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export {};
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import fsExtra from "fs-extra";
2+
import { fileURLToPath } from "url";
3+
4+
// fs-extra is CJS, readJson can't be imported using shorthand
5+
export const { readJson } = fsExtra;
6+
7+
export async function loadConfig(cwd: string) {
8+
// dynamically load NextJS so this can be used in an NPX context
9+
const { NodeJsAsyncHost }: typeof import("@angular-devkit/core/node") = await import(
10+
`${cwd}/node_modules/@angular-devkit/core/node/index.js`
11+
);
12+
const { workspaces }: typeof import("@angular-devkit/core") = await import(
13+
`${cwd}/node_modules/@angular-devkit/core/src/index.js`
14+
);
15+
const { WorkspaceNodeModulesArchitectHost }: typeof import("@angular-devkit/architect/node") =
16+
await import(`${cwd}/node_modules/@angular-devkit/architect/node/index.js`);
17+
18+
const host = workspaces.createWorkspaceHost(new NodeJsAsyncHost());
19+
const { workspace } = await workspaces.readWorkspace(cwd, host);
20+
const architectHost = new WorkspaceNodeModulesArchitectHost(workspace, cwd);
21+
22+
const apps: string[] = [];
23+
workspace.projects.forEach((value, key) => {
24+
if (value.extensions.projectType === "application") apps.push(key);
25+
});
26+
const project = apps[0];
27+
if (apps.length > 1 || !project) throw new Error("Unable to determine the application to deploy");
28+
29+
const workspaceProject = workspace.projects.get(project);
30+
if (!workspaceProject) throw new Error(`No project ${project} found.`);
31+
32+
const target = "build";
33+
if (!workspaceProject.targets.has(target)) throw new Error("Could not find build target.");
34+
35+
const { builder, defaultConfiguration: configuration = "production" } =
36+
workspaceProject.targets.get(target)!;
37+
if (builder !== "@angular-devkit/build-angular:application") {
38+
throw new Error("Only the Angular application builder is supported.");
39+
}
40+
41+
const buildTarget = {
42+
project,
43+
target,
44+
configuration,
45+
};
46+
47+
const options = await architectHost.getOptionsForTarget(buildTarget);
48+
if (!options) throw new Error("Not able to find options for build target.");
49+
return options;
50+
}
51+
52+
export const isMain = (meta: ImportMeta) => {
53+
if (!meta) return false;
54+
if (!process.argv[1]) return false;
55+
return process.argv[1] === fileURLToPath(meta.url);
56+
};
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"extends": "../../../tsconfig.json",
3+
"compilerOptions": {
4+
"noEmit": false,
5+
"outDir": "dist",
6+
"rootDir": "src"
7+
},
8+
"include": [
9+
"src/index.ts",
10+
"src/bin/*.ts",
11+
],
12+
"exclude": [
13+
"src/*.spec.ts"
14+
]
15+
}

0 commit comments

Comments
 (0)