@notation/cli 0.4.2 → 0.6.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/dist/index.js CHANGED
@@ -4,8 +4,7 @@
4
4
  import { program } from "commander";
5
5
 
6
6
  // src/compile.ts
7
- import fs from "fs";
8
- import * as fflate from "fflate";
7
+ import chokidar from "chokidar";
9
8
  import { glob } from "glob";
10
9
  import { log } from "console";
11
10
  import esbuild from "esbuild";
@@ -14,18 +13,29 @@ import {
14
13
  functionRuntimePlugin
15
14
  } from "@notation/esbuild-plugins";
16
15
  import { filePaths } from "@notation/core";
17
- async function compile(entryPoint) {
18
- await compileInfra(entryPoint);
19
- const fnEntryPoints = await glob("**/*.fn.ts");
20
- await compileFns(fnEntryPoints);
21
- await zipFns(fnEntryPoints);
16
+ async function compile(entryPoint, watch2 = false) {
17
+ log(`${watch2 ? "Watching" : "Compiling"} infrastructure`, entryPoint);
18
+ await compileInfra(entryPoint, watch2);
19
+ log(`${watch2 ? "Watching" : "Compiling"} functions`);
20
+ const fnEntryPoints = await glob("runtime/**/*.fn.ts");
21
+ let disposeFnCompiler = await compileFns(fnEntryPoints, watch2);
22
+ if (!watch2)
23
+ return;
24
+ chokidar.watch("**/*.fn.ts", {
25
+ ignored: /node_modules/,
26
+ persistent: true
27
+ }).on("all", async () => {
28
+ if (disposeFnCompiler)
29
+ disposeFnCompiler();
30
+ const fnEntryPoints2 = await glob("runtime/**/*.fn.ts");
31
+ disposeFnCompiler = await compileFns(fnEntryPoints2, watch2);
32
+ });
22
33
  }
23
- async function compileInfra(entryPoint) {
24
- log("Compiling infrastructure", entryPoint);
25
- await esbuild.build({
34
+ async function compileInfra(entryPoint, watch2 = false) {
35
+ const context = await esbuild.context({
26
36
  entryPoints: [entryPoint],
27
37
  plugins: [functionInfraPlugin()],
28
- outdir: "dist/infra",
38
+ outdir: "dist",
29
39
  outbase: ".",
30
40
  outExtension: { ".js": ".mjs" },
31
41
  bundle: true,
@@ -34,11 +44,16 @@ async function compileInfra(entryPoint) {
34
44
  treeShaking: true,
35
45
  packages: "external"
36
46
  });
47
+ if (watch2) {
48
+ await context.watch();
49
+ } else {
50
+ await context.rebuild();
51
+ context.dispose();
52
+ }
37
53
  }
38
- async function compileFns(entryPoints) {
39
- log("Compiling functions");
54
+ async function compileFns(entryPoints, watch2 = false) {
40
55
  for (const entryPoint of entryPoints) {
41
- await esbuild.build({
56
+ const context = await esbuild.context({
42
57
  entryPoints: [entryPoint],
43
58
  plugins: [functionRuntimePlugin()],
44
59
  outfile: filePaths.dist.runtime.index(entryPoint),
@@ -48,46 +63,37 @@ async function compileFns(entryPoints) {
48
63
  platform: "node",
49
64
  treeShaking: true
50
65
  });
51
- }
52
- }
53
- async function zipFns(entryPoints) {
54
- log("Compiling deployable packages");
55
- for (const entryPoint of entryPoints) {
56
- const inputFilePath = filePaths.dist.runtime.index(entryPoint);
57
- const inputFile = fs.readFileSync(inputFilePath);
58
- const zipFilePath = `${inputFilePath}.zip`;
59
- const archive = fflate.zipSync({ "index.mjs": inputFile }, { level: 9 });
60
- fs.writeFileSync(zipFilePath, archive);
66
+ if (watch2) {
67
+ await context.watch();
68
+ return () => context.dispose();
69
+ } else {
70
+ await context.rebuild();
71
+ context.dispose();
72
+ }
61
73
  }
62
74
  }
63
75
 
64
- // src/utils.ts
65
- import path from "path";
66
- import { getResources, getResourceGroups, filePaths as filePaths2 } from "@notation/core";
67
- async function getResourceGraph(entryPoint) {
68
- const outFilePath = filePaths2.dist.infra(entryPoint);
69
- await import(path.join(process.cwd(), outFilePath));
70
- const resourceGroups = getResourceGroups();
71
- const resources = getResources();
72
- return { resourceGroups, resources };
73
- }
74
-
75
76
  // src/deploy.ts
77
+ import { deployApp } from "@notation/core";
76
78
  async function deploy(entryPoint) {
77
79
  await compile(entryPoint);
80
+ console.log(`Deploying ${entryPoint}`);
78
81
  await deployApp(entryPoint);
79
82
  }
80
- async function deployApp(entryPoint) {
81
- console.log(`Deploying ${entryPoint}`);
82
- const graph = await getResourceGraph(entryPoint);
83
- for (const resource of graph.resources) {
84
- await resource.runDeploy();
85
- console.log(`Deployed ${resource.type} ${resource.id}`);
86
- }
83
+
84
+ // src/destroy.ts
85
+ import { destroyApp } from "@notation/core";
86
+ async function destroy(entryPoint) {
87
+ await compile(entryPoint);
88
+ await destroyApp(entryPoint);
87
89
  }
88
90
 
89
91
  // src/visualise.ts
90
- import { createMermaidFlowChart, createMermaidLiveUrl } from "@notation/core";
92
+ import {
93
+ createMermaidFlowChart,
94
+ createMermaidLiveUrl,
95
+ getResourceGraph
96
+ } from "@notation/core";
91
97
  import { log as log2 } from "console";
92
98
  async function visualise(entryPoint) {
93
99
  await compileInfra(entryPoint);
@@ -102,82 +108,66 @@ async function generateGraph(entryPoint) {
102
108
  log2(chartUrl);
103
109
  }
104
110
 
105
- // src/scaffold.ts
106
- import path2 from "node:path";
107
- import fse from "fs-extra";
108
- import { execSync } from "node:child_process";
109
- import whichPmRuns from "which-pm-runs";
110
- var dirname = path2.dirname(new URL(import.meta.url).pathname);
111
- var packageManager = whichPmRuns()?.name || "npm";
112
- var packageManagerInstallCommand = getPmInstallCommand(packageManager);
113
- async function scaffoldApp(appName) {
114
- const cwd = process.cwd();
115
- const appDir = path2.join(cwd, appName);
116
- await fse.ensureDir(appDir);
117
- const children = await fse.readdir(appDir);
118
- if (children.length) {
119
- console.error(
120
- `Directory ${path2.relative(process.cwd(), appDir)} is not empty`
121
- );
122
- return;
123
- }
124
- console.log(`
125
- Creating app from template...`);
126
- const templateDir = path2.join(dirname, "../templates/starter");
127
- await fse.copy(templateDir, appDir);
128
- const packageJsonPath = path2.join(appDir, "package.json");
129
- const packageJsonContent = await fse.readFile(packageJsonPath, "utf8");
130
- const packageJson = JSON.parse(packageJsonContent);
131
- packageJson.name = appName;
132
- const updatedPackageJson = JSON.stringify(packageJson, null, 2);
133
- await fse.writeFile(packageJsonPath, updatedPackageJson, {
134
- encoding: "utf8"
135
- });
136
- console.log(`Installing dependencies with ${packageManager}...`);
137
- execSync(`${packageManagerInstallCommand} @notation/cli @notation/aws`, {
138
- cwd: appDir,
139
- stdio: "inherit"
111
+ // src/watch.ts
112
+ import chokidar2 from "chokidar";
113
+ import { deployApp as deployApp2 } from "@notation/core";
114
+ var dotFilesRe = /(^|[\/\\])\../;
115
+ async function watch(entryPoint) {
116
+ await compile(entryPoint, true);
117
+ const watcher = chokidar2.watch("dist", {
118
+ ignored: dotFilesRe,
119
+ persistent: true
140
120
  });
141
- console.log("\nApp ready! To get started run:\n");
142
- console.log(`\u279C cd ${appName}`);
143
- console.log(`\u279C ${getPmRunCommand(packageManager)} viz`);
144
- }
145
- function getPmInstallCommand(pm) {
146
- switch (pm) {
147
- case "yarn":
148
- return "yarn add";
149
- case "pnpm":
150
- return "pnpm add";
151
- case "bun":
152
- return "bun add";
153
- default:
154
- return "npm install";
121
+ watcher.on("all", debounceDeploy);
122
+ let isDeploying = false;
123
+ let deployQueued = false;
124
+ let timeoutId;
125
+ const debounceTime = 500;
126
+ function debounceDeploy() {
127
+ if (timeoutId) {
128
+ clearTimeout(timeoutId);
129
+ }
130
+ timeoutId = setTimeout(() => {
131
+ triggerDeploy();
132
+ }, debounceTime);
155
133
  }
156
- }
157
- function getPmRunCommand(pm) {
158
- switch (pm) {
159
- case "yarn":
160
- return "yarn";
161
- case "pnpm":
162
- return "pnpm";
163
- case "bun":
164
- return "bun";
165
- default:
166
- return "npm run";
134
+ function triggerDeploy() {
135
+ if (isDeploying) {
136
+ deployQueued = true;
137
+ return;
138
+ }
139
+ isDeploying = true;
140
+ deployApp2(entryPoint, false).then(() => {
141
+ isDeploying = false;
142
+ if (deployQueued) {
143
+ deployQueued = false;
144
+ triggerDeploy();
145
+ }
146
+ }).catch((err) => {
147
+ console.error(err);
148
+ isDeploying = false;
149
+ });
167
150
  }
168
151
  }
169
152
 
170
153
  // src/index.ts
171
- program.command("create").argument("[appName]", "app name", "notation-starter").description("Create Notation App").action(async (appName) => {
172
- await scaffoldApp(appName);
173
- });
154
+ import { startDashboardServer } from "@notation/dashboard";
174
155
  program.command("compile").argument("<entryPoint>", "entryPoint").description("Compile Notation App").action(async (entryPoint) => {
175
156
  await compile(entryPoint);
176
157
  });
177
- program.command("viz").argument("<entryPoint>", "entryPoint").description("Visualise Notation App").action(async (entryPoint) => {
178
- await visualise(entryPoint);
158
+ program.command("dashboard").description("Start Notation Dashboard").action(async () => {
159
+ await startDashboardServer();
179
160
  });
180
161
  program.command("deploy").argument("<entryPoint>", "entryPoint").description("Deploy Notation App").action(async (entryPoint) => {
181
162
  await deploy(entryPoint);
182
163
  });
164
+ program.command("destroy").argument("<entryPoint>", "entryPoint").description("Destroy Notation App").action(async (entryPoint) => {
165
+ await destroy(entryPoint);
166
+ });
167
+ program.command("viz").argument("<entryPoint>", "entryPoint").description("Visualise Notation App").action(async (entryPoint) => {
168
+ await visualise(entryPoint);
169
+ });
170
+ program.command("watch").argument("<entryPoint>", "entryPoint").description("Watch Notation App").action(async (entryPoint) => {
171
+ await watch(entryPoint);
172
+ });
183
173
  program.parse(process.argv);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@notation/cli",
4
- "version": "0.4.2",
4
+ "version": "0.6.0",
5
5
  "files": [
6
6
  "dist",
7
7
  "templates"
@@ -10,19 +10,19 @@
10
10
  "notation": "dist/index.js"
11
11
  },
12
12
  "dependencies": {
13
- "@types/fs-extra": "^11.0.4",
14
- "@types/which-pm-runs": "^1.0.2",
13
+ "chokidar": "^3.5.3",
15
14
  "commander": "^11.0.0",
16
15
  "esbuild": "^0.19.3",
17
- "fflate": "0.8.1",
18
- "fs-extra": "^11.1.1",
19
16
  "glob": "^10.3.10",
20
- "which-pm-runs": "^1.1.0",
21
- "@notation/core": "0.3.1",
22
- "@notation/esbuild-plugins": "0.3.1"
17
+ "@notation/core": "0.4.1",
18
+ "@notation/esbuild-plugins": "0.4.0",
19
+ "@notation/dashboard": "0.1.0"
20
+ },
21
+ "devDependencies": {
22
+ "@types/which-pm-runs": "^1.0.2"
23
23
  },
24
24
  "scripts": {
25
- "build": "tsup",
25
+ "build": "tsup --clean",
26
26
  "dev": "npm run build -- --watch"
27
27
  }
28
28
  }
@@ -1,7 +0,0 @@
1
- {
2
- "private": true,
3
- "name": "notation-starter",
4
- "scripts": {
5
- "viz": "notation viz src/api.ts"
6
- }
7
- }
@@ -1,8 +0,0 @@
1
- import { api, router } from "@notation/aws/api-gateway";
2
- import { getTodos, getTodoCount } from "./todos/todos.fn";
3
-
4
- const todoApi = api({ name: "todo-api" });
5
- const todoRouter = router(todoApi);
6
-
7
- todoRouter.get("/todos", getTodos);
8
- todoRouter.get("/todos/count", getTodoCount);
@@ -1,19 +0,0 @@
1
- import type { LambdaConfig } from "@notation/aws/lambda.fn";
2
- import { handle, json } from "@notation/aws/lambda.fn";
3
- import { api } from "./utils";
4
-
5
- const todos = await api.get<any[]>("/todos");
6
-
7
- export const getTodos = handle.apiRequest(() => {
8
- return json(todos);
9
- });
10
-
11
- export const getTodoCount = handle.apiRequest(() => {
12
- return json(todos.length);
13
- });
14
-
15
- export const config: LambdaConfig = {
16
- service: "aws/lambda",
17
- timeout: 5,
18
- memory: 64,
19
- };
@@ -1,6 +0,0 @@
1
- export const api = {
2
- get: async <T = any>(path: string) => {
3
- const res = await fetch(`https://jsonplaceholder.typicode.com${path}`);
4
- return res.json() as Promise<T>;
5
- },
6
- };
@@ -1,27 +0,0 @@
1
- {
2
- "$schema": "https://json.schemastore.org/tsconfig",
3
- "display": "Default",
4
- "compilerOptions": {
5
- "lib": ["esnext"],
6
- "module": "esnext",
7
- "target": "esnext",
8
-
9
- "moduleResolution": "bundler",
10
- "noEmit": true,
11
-
12
- "composite": false,
13
- "declaration": true,
14
- "declarationMap": true,
15
- "forceConsistentCasingInFileNames": true,
16
- "inlineSources": false,
17
- "isolatedModules": true,
18
- "noUnusedLocals": false,
19
- "noUnusedParameters": false,
20
- "preserveWatchOutput": true,
21
- "skipDefaultLibCheck": true,
22
- "skipLibCheck": true,
23
- "strict": true,
24
- "strictNullChecks": true
25
- },
26
- "exclude": ["node_modules"]
27
- }