Skip to content

Commit

Permalink
More stuffs (#117)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
jamesdaniels authored Dec 14, 2023
1 parent b91c223 commit a076bd8
Show file tree
Hide file tree
Showing 28 changed files with 4,680 additions and 889 deletions.
4,689 changes: 3,916 additions & 773 deletions package-lock.json

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,17 @@
"packages/**/*"
],
"devDependencies": {
"@types/mocha": "*",
"@typescript-eslint/eslint-plugin": "^6.10.0",
"eslint": "^8.53.0",
"eslint-config-google": "^0.14.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-jsdoc": "^46.8.2",
"eslint-plugin-prettier": "^5.0.1",
"lerna": "^7.4.0",
"mocha": "^10.2.0",
"prettier": "^3.0.3",
"ts-mocha": "^10.0.0",
"typescript": "^5.2.0"
}
}
1 change: 1 addition & 0 deletions packages/@apphosting/adapter-angular/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/e2e
69 changes: 69 additions & 0 deletions packages/@apphosting/adapter-angular/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
{
"name": "@apphosting/adapter-angular",
"version": "17.0.0",
"main": "dist/index.js",
"description": "Experimental addon to the Firebase CLI to add web framework support",
"repository": {
"type": "git",
"url": "git+https://github.com/FirebaseExtended/firebase-framework-tools.git"
},
"bin": {
"apphosting-adapter-angular-build": "dist/bin/build.js",
"apphosting-adapter-angular-create": "dist/bin/create.js"
},
"author": {
"name": "Firebase",
"url": "https://firebase.google.com/"
},
"bugs": {
"url": "https://github.com/FirebaseExtended/firebase-framework-tools/issues"
},
"type": "module",
"sideEffects": false,
"scripts": {
"build": "rm -rf dist && tsc && chmod +x ./dist/bin/*",
"test": "ts-mocha -p tsconfig.json src/**/*.spec.ts"
},
"exports": {
".": {
"node": "./dist/index.js",
"default": null
},
"./dist/*": {
"node": "./dist/*",
"default": null
}
},
"files": [
"dist"
],
"license": "Apache-2.0",
"dependencies": {
"fs-extra": "*",
"yaml": "*",
"tslib": "*",
"@npmcli/run-script": "*"
},
"peerDependencies": {
"@angular-devkit/architect": "~0.1700.0",
"@angular-devkit/core": "~17.0.0"
},
"peerDependenciesMeta": {
"@angular-devkit/architect": { "optional": true },
"@angular-devkit/core": { "optional": true }
},
"devDependencies": {
"@angular-devkit/architect": "~0.1700.0",
"@angular-devkit/core": "~17.0.0",
"@angular/core": "~17.0.0",
"@types/fs-extra": "*",
"@types/mocha": "*",
"@types/tmp": "*",
"semver": "*",
"tmp": "*",
"ts-node": "*",
"mocha": "*",
"ts-mocha": "*",
"typescript": "*"
}
}
22 changes: 22 additions & 0 deletions packages/@apphosting/adapter-angular/src/bin/build.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#! /usr/bin/env node
import { spawn } from "child_process";
import { loadConfig } from "../utils.js";

const build = (cwd = process.cwd()) =>
new Promise<void>((resolve, reject) => {
// TODO warn if the build script contains anything other than `ng build`
const process = spawn("npm", ["run", "build"], { cwd, shell: true, stdio: "pipe" });
process.stdout.on("data", (it: Buffer) => console.log(it.toString().trim()));
process.stderr.on("data", (it: Buffer) => console.error(it.toString().trim()));
process.on("exit", (code) => {
if (code === 0) return resolve();
reject();
});
});

const config = await loadConfig(process.cwd());

await build().catch(() => process.exit(1));

// TODO do all the things
console.log({ config });
39 changes: 39 additions & 0 deletions packages/@apphosting/adapter-angular/src/bin/create.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import assert from "assert";
import { parse } from "semver";
import fsExtra from "fs-extra";

const { readJson } = fsExtra;

const readPackageJson = readJson("package.json");
const importCreateJs = import("@apphosting/adapter-angular/dist/bin/create.js");

describe("peer dependencies", async () => {

let expectedAngularRange: string;
let exepctedDevKitArchitectRange: string;

before(async () => {
const packageJson = await readPackageJson;
const version = parse(packageJson.version);
if (!version) throw "couldn't parse package.json version";
expectedAngularRange = `~${version.major}.${version.minor}.0`;
exepctedDevKitArchitectRange = `~0.${version.major}${version.minor < 10 ? '0' : ''}${version.minor}.0`;
});

it("expected @angular/cli version requirement to match", async () => {
const { ANGULAR_CLI_VERSION } = await importCreateJs;
assert.equal(expectedAngularRange, ANGULAR_CLI_VERSION);
});

it("expected @angular-devkit/architect version requirement to match", async () => {
const packageJson = await readPackageJson;
const devKitArchitectRange = packageJson.peerDependencies["@angular-devkit/architect"];
assert.equal(exepctedDevKitArchitectRange, devKitArchitectRange);
});

it("expected @angular-devkit/core version requirement to match", async () => {
const packageJson = await readPackageJson;
const devKitCoreRange = packageJson.peerDependencies["@angular-devkit/core"];
assert.equal(expectedAngularRange, devKitCoreRange);
});
});
61 changes: 61 additions & 0 deletions packages/@apphosting/adapter-angular/src/bin/create.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#! /usr/bin/env node
import { spawn } from "child_process";

import { isMain } from "../utils.js";

export const ANGULAR_CLI_VERSION = "~17.0.0";

const main = isMain(import.meta);

// TODO can we write a test to see if we're capturing all options from --help?
const enum Options {
help = "--help",
interactive = "--interactive",
dryRun = "--dry-run",
defaults = "--defaults",
force = "--force",
collection = "--collection",
commit = "--commit",
createApplication = "--create-application",
directory = "--directory",
inlineStyle = "--inline-style",
inlineTemplate = "--inline-template",
minimal = "--minimal",
newProjecRoot = "--new-project-root",
packageManager = "--package-manager",
prefix = "--prefix",
routing = "--routing",
skipGit = "--skip-git",
skipInstall = "--skip-install",
skipTests = "--skip-tests",
ssr = "--ssr",
standalone = "--standalone",
strict = "--strict",
style = "--style",
viewEncapsulation = "--view-encapsulation",
}

export async function create(projectDirectory = process.argv[2], cwd = process.cwd()) {
return await new Promise<void>((resolve, reject) => {
const args = [
"-y",
"-p",
`@angular/cli@${ANGULAR_CLI_VERSION}`,
"ng",
"new",
"hello-world",
Options.directory,
projectDirectory,
Options.skipGit,
];
const process = spawn("npx", args, { cwd, shell: true, stdio: "inherit" });
process.on("exit", (code) => {
if (code === 0) return resolve();
reject();
});
});
}

if (main) {
await create().catch(() => process.exit(1));
}
1 change: 1 addition & 0 deletions packages/@apphosting/adapter-angular/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export {};
56 changes: 56 additions & 0 deletions packages/@apphosting/adapter-angular/src/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import fsExtra from "fs-extra";
import { fileURLToPath } from "url";

// fs-extra is CJS, readJson can't be imported using shorthand
export const { readJson } = fsExtra;

export async function loadConfig(cwd: string) {
// dynamically load NextJS so this can be used in an NPX context
const { NodeJsAsyncHost }: typeof import("@angular-devkit/core/node") = await import(
`${cwd}/node_modules/@angular-devkit/core/node/index.js`
);
const { workspaces }: typeof import("@angular-devkit/core") = await import(
`${cwd}/node_modules/@angular-devkit/core/src/index.js`
);
const { WorkspaceNodeModulesArchitectHost }: typeof import("@angular-devkit/architect/node") =
await import(`${cwd}/node_modules/@angular-devkit/architect/node/index.js`);

const host = workspaces.createWorkspaceHost(new NodeJsAsyncHost());
const { workspace } = await workspaces.readWorkspace(cwd, host);
const architectHost = new WorkspaceNodeModulesArchitectHost(workspace, cwd);

const apps: string[] = [];
workspace.projects.forEach((value, key) => {
if (value.extensions.projectType === "application") apps.push(key);
});
const project = apps[0];
if (apps.length > 1 || !project) throw new Error("Unable to determine the application to deploy");

const workspaceProject = workspace.projects.get(project);
if (!workspaceProject) throw new Error(`No project ${project} found.`);

const target = "build";
if (!workspaceProject.targets.has(target)) throw new Error("Could not find build target.");

const { builder, defaultConfiguration: configuration = "production" } =
workspaceProject.targets.get(target)!;
if (builder !== "@angular-devkit/build-angular:application") {
throw new Error("Only the Angular application builder is supported.");
}

const buildTarget = {
project,
target,
configuration,
};

const options = await architectHost.getOptionsForTarget(buildTarget);
if (!options) throw new Error("Not able to find options for build target.");
return options;
}

export const isMain = (meta: ImportMeta) => {
if (!meta) return false;
if (!process.argv[1]) return false;
return process.argv[1] === fileURLToPath(meta.url);
};
15 changes: 15 additions & 0 deletions packages/@apphosting/adapter-angular/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"extends": "../../../tsconfig.json",
"compilerOptions": {
"noEmit": false,
"outDir": "dist",
"rootDir": "src"
},
"include": [
"src/index.ts",
"src/bin/*.ts",
],
"exclude": [
"src/*.spec.ts"
]
}
18 changes: 11 additions & 7 deletions packages/@apphosting/adapter-nextjs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,16 @@
"sideEffects": false,
"scripts": {
"build": "rm -rf dist && tsc && chmod +x ./dist/bin/*",
"test": "node --loader ts-node/esm ./test.ts"
"test": "ts-mocha -p tsconfig.json src/**/*.spec.ts"
},
"exports": {
".": {
"node": "./dist/index.js",
"default": null
},
"./dist/*": {
"node": "./dist/*",
"default": null
}
},
"files": [
Expand All @@ -39,19 +43,19 @@
"yaml": "^2.3.4"
},
"peerDependencies": {
"next": "~14.0.0 || ~14.0.0-0"
"next": "~14.0.0"
},
"peerDependenciesMeta": {
"next": {
"optional": true
}
},
"devDependencies": {
"@types/fs-extra": "^11.0.4",
"@types/tmp": "^0.2.6",
"@types/fs-extra": "*",
"@types/tmp": "*",
"next": "~14.0.0",
"semver": "^7.5.4",
"tmp": "^0.2.1",
"ts-node": "^10.9.1"
"semver": "*",
"tmp": "*",
"ts-node": "*"
}
}
31 changes: 31 additions & 0 deletions packages/@apphosting/adapter-nextjs/src/bin/create.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import assert from "assert";
import { parse } from "semver";
import fsExtra from "fs-extra";

const { readJson } = fsExtra;

const readPackageJson = readJson("package.json");
const importCreateJs = import("@apphosting/adapter-nextjs/dist/bin/create.js");

describe("peer dependencies", async () => {

let expectedNextJSRange: string;

before(async () => {
const packageJson = await readPackageJson;
const version = parse(packageJson.version);
if (!version) throw "couldn't parse package.json version";
expectedNextJSRange = `~${version.major}.${version.minor}.0`;
});

it("expected create-next-app version requirement to match", async () => {
const { CREATE_NEXT_APP_VERSION } = await importCreateJs;
assert.equal(expectedNextJSRange, CREATE_NEXT_APP_VERSION);
});

it("expected next version requirement to match", async () => {
const packageJson = await readPackageJson;
const nextVersionRange = packageJson.peerDependencies["next"];
assert.equal(expectedNextJSRange, nextVersionRange);
});
});
Loading

0 comments on commit a076bd8

Please sign in to comment.