@marko/run 0.1.4 → 0.1.6

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.
@@ -3,7 +3,7 @@ import path2 from "path";
3
3
  import crypto from "crypto";
4
4
  import fs2 from "fs";
5
5
  import glob from "glob";
6
- import { mergeConfig, resolvePackageData } from "vite";
6
+ import { mergeConfig } from "vite";
7
7
  import markoVitePlugin, { FileStore } from "@marko/vite";
8
8
 
9
9
  // src/vite/constants.ts
@@ -643,7 +643,9 @@ function renderRouter(routes, options = {
643
643
  `import page${key} from '${virtualFilePrefix}/${markoRunFilePrefix}special__${key}.marko${serverEntryQuery}';`
644
644
  );
645
645
  }
646
- writer.writeLines("").writeBlockStart(`export function match(method, pathname) {`).writeLines(
646
+ writer.writeLines(`
647
+ globalThis.__marko_run__ = { match, fetch, invoke };
648
+ `).writeBlockStart(`export function match(method, pathname) {`).writeLines(
647
649
  `if (!pathname) {
648
650
  pathname = '/';
649
651
  } else if (pathname.charAt(0) !== '/') {
@@ -792,7 +794,7 @@ function writeRouterVerb(writer, trie, verb, level = 0, offset = 1) {
792
794
  if (terminal || (dynamic == null ? void 0 : dynamic.route)) {
793
795
  closeCount++;
794
796
  writer.writeBlockStart(`if (!${index} || ${index} === len) {`);
795
- let value = `pathname.slice(${offset}, ${index} ? -1 : len)`;
797
+ let value = `decodeURIComponent(pathname.slice(${offset}, ${index} ? -1 : len))`;
796
798
  if (dynamic == null ? void 0 : dynamic.route) {
797
799
  const segment = `s${next}`;
798
800
  writer.writeLines(`const ${segment} = ${value};`);
@@ -831,7 +833,7 @@ function writeRouterVerb(writer, trie, verb, level = 0, offset = 1) {
831
833
  writer.writeBlockStart(`if (${index} && ${index} !== len) {`);
832
834
  closeCount++;
833
835
  }
834
- let value = `pathname.slice(${offset}, ${index} - 1)`;
836
+ let value = `decodeURIComponent(pathname.slice(${offset}, ${index} - 1))`;
835
837
  if ((dynamic == null ? void 0 : dynamic.static) || (dynamic == null ? void 0 : dynamic.dynamic)) {
836
838
  const segment = `s${next}`;
837
839
  writer.writeLines(`const ${segment} = ${value};`);
@@ -843,11 +845,12 @@ function writeRouterVerb(writer, trie, verb, level = 0, offset = 1) {
843
845
  writer.writeBlockStart(`switch (${value}.toLowerCase()) {`);
844
846
  }
845
847
  for (const child of children) {
848
+ const decodedKey = decodeURIComponent(child.key);
846
849
  if (useSwitch) {
847
- writer.writeBlockStart(`case '${child.key}': {`);
850
+ writer.writeBlockStart(`case '${decodedKey}': {`);
848
851
  } else {
849
852
  writer.writeBlockStart(
850
- `if (${value}.toLowerCase() === '${child.key}') {`
853
+ `if (${value}.toLowerCase() === '${decodedKey}') {`
851
854
  );
852
855
  }
853
856
  const nextOffset = typeof offset === "string" ? index : offset + child.key.length + 1;
@@ -877,6 +880,7 @@ function writeRouterVerb(writer, trie, verb, level = 0, offset = 1) {
877
880
  }
878
881
  }
879
882
  function wrapPropertyName(name) {
883
+ name = decodeURIComponent(name);
880
884
  return /^[^A-Za-z_$]|[^A-Za-z0-9$_]/.test(name) ? `'${name}'` : name;
881
885
  }
882
886
  function renderParamsInfo(params, pathIndex) {
@@ -977,7 +981,10 @@ interface NoMeta {}
977
981
  const routeType = `Route${route.index}`;
978
982
  const pathType = `\`${route.path.replace(
979
983
  /\/\$(\$?)([^\/]*)/,
980
- (_, catchAll, name) => catchAll ? `/:${name || "rest"}*` : `/:${name}`
984
+ (_, catchAll, name) => {
985
+ name = decodeURIComponent(name);
986
+ return catchAll ? `/:${name || "rest"}*` : `/:${name}`;
987
+ }
981
988
  )}\``;
982
989
  const paramsType = (params == null ? void 0 : params.length) ? renderParamsInfoType(params) : "NoParams";
983
990
  let metaType = "NoMeta";
@@ -985,10 +992,10 @@ interface NoMeta {}
985
992
  const isGet = page || ((_a = handler == null ? void 0 : handler.verbs) == null ? void 0 : _a.includes("get"));
986
993
  const isPost = (_b = handler == null ? void 0 : handler.verbs) == null ? void 0 : _b.includes("post");
987
994
  if (isGet || isPost) {
988
- const path3 = route.path.replace(
989
- /\$(\$?)([^/]+)/g,
990
- (_, s, name) => s ? `\${...${name}}` : `\${${name}}`
991
- );
995
+ const path3 = route.path.replace(/\$(\$?)([^/]+)/g, (_, catchAll, name) => {
996
+ name = decodeURIComponent(name);
997
+ return catchAll ? `\${...${name}}` : `\${${name}}`;
998
+ });
992
999
  const splatIndex = path3.indexOf("/${...");
993
1000
  if (splatIndex >= 0) {
994
1001
  const path22 = path3.slice(0, splatIndex) || "/";
@@ -1199,9 +1206,9 @@ function getExportIdentifiers(astProgramNode) {
1199
1206
  }
1200
1207
 
1201
1208
  // src/vite/utils/log.ts
1209
+ import zlib from "node:zlib";
1202
1210
  import Table from "cli-table3";
1203
1211
  import kleur from "kleur";
1204
- import { gzipSizeSync } from "gzip-size";
1205
1212
  import format from "human-format";
1206
1213
  var HttpVerbColors = {
1207
1214
  get: kleur.green,
@@ -1287,17 +1294,20 @@ function computeRouteSize(route, bundle) {
1287
1294
  }
1288
1295
  return [0, 0];
1289
1296
  }
1290
- function byteSize(str) {
1291
- return new Blob([str]).size;
1297
+ function gzipSize(source) {
1298
+ return zlib.gzipSync(source, { level: 9 }).length;
1299
+ }
1300
+ function byteSize(source) {
1301
+ return new Blob([source]).size;
1292
1302
  }
1293
1303
  function computeChunkSize(chunk, bundle, seen = /* @__PURE__ */ new Set()) {
1294
1304
  if (chunk.type === "asset") {
1295
1305
  return [
1296
1306
  byteSize(chunk.source),
1297
- gzipSizeSync(chunk.source)
1307
+ gzipSize(chunk.source)
1298
1308
  ];
1299
1309
  }
1300
- const size = [byteSize(chunk.code), gzipSizeSync(chunk.code)];
1310
+ const size = [byteSize(chunk.code), gzipSize(chunk.code)];
1301
1311
  for (const id of chunk.imports) {
1302
1312
  if (!seen.has(id)) {
1303
1313
  const [bytes, compBytes] = computeChunkSize(bundle[id], bundle, seen);
@@ -1386,7 +1396,7 @@ function markoRun(opts = {}) {
1386
1396
  const filepath = path2.join(typesDir, "routes.d.ts");
1387
1397
  const data = await renderRouteTypeInfo(
1388
1398
  routes,
1389
- path2.relative(typesDir, routesDir),
1399
+ path2.relative(typesDir, resolvedRoutesDir),
1390
1400
  adapter
1391
1401
  );
1392
1402
  if (data !== typesFile || !fs2.existsSync(filepath)) {
@@ -1499,6 +1509,9 @@ function markoRun(opts = {}) {
1499
1509
  define: isBuild ? {
1500
1510
  "process.env.NODE_ENV": "'production'"
1501
1511
  } : void 0,
1512
+ ssr: {
1513
+ noExternal: /@marko\/run/
1514
+ },
1502
1515
  build: {
1503
1516
  emptyOutDir: isSSRBuild
1504
1517
  }
@@ -1736,6 +1749,7 @@ async function resolveAdapter(root, options, log) {
1736
1749
  if (adapter !== void 0) {
1737
1750
  return adapter;
1738
1751
  }
1752
+ const { resolvePackageData } = await import("vite");
1739
1753
  const pkg = resolvePackageData(".", root);
1740
1754
  if (pkg) {
1741
1755
  const dependecies = { ...pkg.data.dependecies, ...pkg.data.devDependencies };
@@ -1762,6 +1776,7 @@ import net from "net";
1762
1776
  import cp from "child_process";
1763
1777
  import { parse, config } from "dotenv";
1764
1778
  import fs3 from "fs";
1779
+ import cluster from "cluster";
1765
1780
  async function parseEnv(envFile) {
1766
1781
  if (fs3.existsSync(envFile)) {
1767
1782
  const content = await fs3.promises.readFile(envFile, "utf8");
@@ -1771,14 +1786,14 @@ async function parseEnv(envFile) {
1771
1786
  function loadEnv(envFile) {
1772
1787
  config({ path: envFile });
1773
1788
  }
1774
- async function spawnServer(cmd, port = 0, env, cwd = process.cwd(), wait = 3e4) {
1789
+ async function spawnServer(cmd, args = [], port = 0, env, cwd = process.cwd(), wait = 3e4) {
1775
1790
  if (port <= 0) {
1776
1791
  port = await getAvailablePort();
1777
1792
  }
1778
1793
  if (typeof env === "string") {
1779
1794
  env = await parseEnv(env);
1780
1795
  }
1781
- const proc = cp.spawn(cmd, {
1796
+ const proc = cp.spawn(cmd, args, {
1782
1797
  cwd,
1783
1798
  shell: true,
1784
1799
  stdio: "inherit",
@@ -1789,32 +1804,45 @@ async function spawnServer(cmd, port = 0, env, cwd = process.cwd(), wait = 3e4)
1789
1804
  proc.unref();
1790
1805
  proc.kill();
1791
1806
  };
1807
+ try {
1808
+ await waitForServer(port, wait);
1809
+ } catch (err) {
1810
+ close();
1811
+ throw err;
1812
+ }
1813
+ return {
1814
+ port,
1815
+ close
1816
+ };
1817
+ }
1818
+ async function waitForServer(port, wait = 0) {
1792
1819
  let remaining = wait > 0 ? wait : Infinity;
1793
- while (!await isPortInUse(port)) {
1820
+ let connection;
1821
+ while (!(connection = await getConnection(port))) {
1794
1822
  if (remaining >= 100) {
1795
1823
  remaining -= 100;
1796
1824
  await sleep(100);
1797
1825
  } else {
1798
- close();
1799
1826
  throw new Error(
1800
1827
  `site-write: timeout while wating for server to start on port "${port}".`
1801
1828
  );
1802
1829
  }
1803
1830
  }
1804
- return {
1805
- port,
1806
- close
1807
- };
1831
+ return connection;
1808
1832
  }
1809
- async function isPortInUse(port) {
1833
+ async function getConnection(port) {
1810
1834
  return new Promise((resolve) => {
1811
- const connection = net.connect(port).setNoDelay(true).setKeepAlive(false).on("error", () => done(false)).on("connect", () => done(true));
1812
- function done(connected) {
1835
+ const connection = net.connect(port).setNoDelay(true).setKeepAlive(false).on("error", () => {
1813
1836
  connection.end();
1814
- resolve(connected);
1815
- }
1837
+ resolve(null);
1838
+ }).on("connect", () => {
1839
+ resolve(connection);
1840
+ });
1816
1841
  });
1817
1842
  }
1843
+ async function isPortInUse(port) {
1844
+ return Boolean(await getConnection(port));
1845
+ }
1818
1846
  async function getAvailablePort() {
1819
1847
  return new Promise((resolve) => {
1820
1848
  const server = net.createServer().listen(0, () => {
@@ -1,19 +1,31 @@
1
1
  import type { RoutableFileType, HttpVerb, RoutableFileTypes } from "./constants";
2
2
  import type { Options as MarkoViteOptions } from "@marko/vite";
3
- import type { ResolvedConfig, UserConfig } from "vite";
3
+ import type { ResolvedConfig, UserConfig, InlineConfig } from "vite";
4
+ import type { SpawnedServer } from "./utils/server";
4
5
  export type { RoutableFileType, HttpVerb };
5
6
  export type StartServer = (port?: number) => Promise<void>;
6
7
  export interface AdapterConfig {
7
8
  [name: PropertyKey]: any;
8
9
  }
10
+ export interface StartOptions {
11
+ cwd: string;
12
+ args: string[];
13
+ port?: number;
14
+ envFile?: string;
15
+ }
16
+ export interface StartDevOptions extends StartOptions {
17
+ }
18
+ export interface StartPreviewOptions extends StartOptions {
19
+ dir: string;
20
+ }
9
21
  export interface Adapter {
10
22
  readonly name: string;
11
23
  configure?(config: AdapterConfig): void;
12
24
  pluginOptions?(options: Options): Promise<Options> | Options | undefined;
13
25
  viteConfig?(config: UserConfig): Promise<UserConfig> | UserConfig | undefined;
14
26
  getEntryFile?(): Promise<string> | string;
15
- startDev?(configFile: string, port: number, envFile?: string): Promise<void> | void;
16
- startPreview?(dir: string, entry?: string, port?: number, envFile?: string): Promise<void> | void;
27
+ startDev?(entry: string | undefined, config: InlineConfig, options: StartDevOptions): Promise<SpawnedServer> | SpawnedServer;
28
+ startPreview?(entry: string | undefined, options: StartPreviewOptions): Promise<SpawnedServer> | SpawnedServer;
17
29
  buildEnd?(config: ResolvedConfig, routes: Route[], builtEntries: string[], sourceEntries: string[]): Promise<void> | void;
18
30
  typeInfo?(writer: (data: string) => void): Promise<string> | string;
19
31
  }
@@ -1,9 +1,15 @@
1
+ /// <reference types="node" />
2
+ import { type Socket } from "net";
3
+ import { type Worker } from "cluster";
1
4
  export interface SpawnedServer {
2
5
  port: number;
3
- close(): void;
6
+ close(): Promise<void> | void;
4
7
  }
5
8
  export declare function parseEnv(envFile: string): Promise<import("dotenv").DotenvParseOutput | undefined>;
6
9
  export declare function loadEnv(envFile: string): void;
7
- export declare function spawnServer(cmd: string, port?: number, env?: string | Record<string, string>, cwd?: string, wait?: number): Promise<SpawnedServer>;
10
+ export declare function spawnServer(cmd: string, args?: string[], port?: number, env?: string | Record<string, string>, cwd?: string, wait?: number): Promise<SpawnedServer>;
11
+ export declare function spawnServerWorker(module: string, args?: string[], port?: number, env?: string | Record<string, string>): Promise<Worker>;
12
+ export declare function waitForServer(port: number, wait?: number): Promise<Socket>;
13
+ export declare function getConnection(port: number): Promise<Socket | null>;
8
14
  export declare function isPortInUse(port: number): Promise<boolean>;
9
15
  export declare function getAvailablePort(): Promise<number>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marko/run",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "The Marko application framework.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/marko-js/run/tree/main/packages/run",
@@ -20,11 +20,10 @@
20
20
  "marko-run": "./dist/cli/index.mjs"
21
21
  },
22
22
  "scripts": {
23
- "mocha": "cross-env NODE_ENV=test mocha \"./src/**/__tests__/*.test.ts\"",
24
- "test": "npm run mocha",
25
- "test:watch": "npm run mocha -- --watch",
23
+ "test": "cross-env NODE_ENV=test mocha \"./src/**/__tests__/*.test.ts\"",
24
+ "test:watch": "npm test -- --watch",
26
25
  "test:inspect": "npm test -- --inspect",
27
- "test:update": "npm run mocha -- --update",
26
+ "test:update": "npm test -- --update",
28
27
  "build": "tsc -b && tsx scripts/build.ts"
29
28
  },
30
29
  "exports": {
@@ -83,17 +82,26 @@
83
82
  },
84
83
  "devDependencies": {
85
84
  "@babel/types": "^7.19.0",
85
+ "@marko/fixture-snapshots": "^2.1.7",
86
+ "@marko/testing-library": "^6.1.2",
86
87
  "@types/glob": "^8.0.1",
87
88
  "@types/human-format": "^1.0.0",
89
+ "@types/jsdom": "^21.1.0",
88
90
  "@types/mocha": "^9.1.1",
89
91
  "@types/node": "^18.11.18",
90
92
  "acorn": "^8.8.0",
91
93
  "cross-env": "^7.0.3",
92
94
  "esbuild": "^0.15.7",
95
+ "jsdom": "^21.1.1",
93
96
  "marko": "^5.23.0",
94
- "mocha": "^10.0.0",
97
+ "mocha": "^10.2.0",
95
98
  "mocha-snap": "^4.3.0",
99
+ "playwright": "^1.29.1",
96
100
  "prettier": "^2.7.1",
101
+ "ts-mocha": "^10.0.0",
102
+ "ts-node": "^10.9.1",
103
+ "tslib": "^2.5.0",
104
+ "tsm": "^2.3.0",
97
105
  "tsx": "^3.9.0",
98
106
  "typescript": "^4.7.4"
99
107
  },
@@ -103,9 +111,9 @@
103
111
  "compression": "^1.7.4",
104
112
  "dotenv": "^16.0.3",
105
113
  "glob": "^8.1.0",
106
- "gzip-size": "^7.0.0",
107
114
  "human-format": "^1.0.0",
108
115
  "kleur": "^4.1.5",
116
+ "parse-node-args": "^1.1.2",
109
117
  "sade": "^1.8.1",
110
118
  "serve-static": "^1.15.0",
111
119
  "strip-ansi": "^7.0.1",