xpine 0.0.24 → 0.0.27

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.
@@ -11,12 +11,146 @@ import chokidar from "chokidar";
11
11
  import path5 from "path";
12
12
  import fs5 from "fs-extra";
13
13
  import { build } from "esbuild";
14
- import ts3 from "typescript";
15
14
 
16
15
  // src/build/typescript-builder.ts
17
16
  import ts from "typescript";
18
17
  import fs from "fs-extra";
18
+ import path2 from "path";
19
+
20
+ // src/util/get-config.ts
19
21
  import path from "path";
22
+
23
+ // src/util/require.ts
24
+ import { createRequire } from "module";
25
+ var require_default = createRequire(import.meta.url);
26
+
27
+ // src/util/get-config.ts
28
+ var rootDir = process.cwd();
29
+ function fromRoot(pathName) {
30
+ if (!pathName) return rootDir;
31
+ return path.join(rootDir, pathName);
32
+ }
33
+ var userConfig = require_default(path.join(process.cwd(), "./xpine.config.mjs")).default;
34
+ var configDefaults = {
35
+ rootDir: fromRoot(),
36
+ srcDir: fromRoot("./src"),
37
+ distDir: fromRoot("./dist"),
38
+ packageJsonPath: fromRoot("package.json"),
39
+ // We need to use getters here in the event someone wants to change folders, such as the dist folder
40
+ get distPublicDir() {
41
+ return path.join(this.distDir, "./public");
42
+ },
43
+ get distPublicScriptsDir() {
44
+ return path.join(this.distPublicDir, "./scripts");
45
+ },
46
+ get distTempFolder() {
47
+ return path.join(this.distDir, "./temp");
48
+ },
49
+ get clientJSBundlePath() {
50
+ return path.join(this.distPublicScriptsDir, "./app.js");
51
+ },
52
+ get alpineDataPath() {
53
+ return path.join(this.distTempFolder, "./alpine-data.ts");
54
+ },
55
+ get serverDistDir() {
56
+ return path.join(this.distDir, "./server");
57
+ },
58
+ get serverDistAppPath() {
59
+ return path.join(this.serverDistDir, "./app.js");
60
+ },
61
+ // Important dirs/paths
62
+ get pagesDir() {
63
+ return path.join(this.srcDir, "./pages");
64
+ },
65
+ get distPagesDir() {
66
+ return path.join(this.distDir, "./pages");
67
+ },
68
+ get publicDir() {
69
+ return path.join(this.srcDir, "./public");
70
+ },
71
+ get serverDir() {
72
+ return path.join(this.srcDir, "./server");
73
+ },
74
+ get runDir() {
75
+ return path.join(this.serverDir, "./run");
76
+ },
77
+ get serverAppPath() {
78
+ return path.join(this.serverDir, "./app.ts");
79
+ },
80
+ get globalCSSFile() {
81
+ return path.join(this.publicDir, "./styles/global.css");
82
+ }
83
+ };
84
+ var config = {
85
+ ...configDefaults,
86
+ ...userConfig
87
+ };
88
+
89
+ // src/context.ts
90
+ function createContext(value) {
91
+ let stateValue = value;
92
+ let arrayQueue = {};
93
+ return {
94
+ get(id) {
95
+ const val = stateValue[id];
96
+ if (Array.isArray(val)) return val.filter((item) => item !== void 0);
97
+ return val;
98
+ },
99
+ set(id, callback, defaultValue) {
100
+ if (!stateValue[id]) stateValue[id] = defaultValue ?? null;
101
+ stateValue[id] = callback(stateValue[id]);
102
+ },
103
+ clear() {
104
+ stateValue = {};
105
+ },
106
+ getAll() {
107
+ return stateValue;
108
+ },
109
+ getArrayQueue() {
110
+ return arrayQueue;
111
+ },
112
+ addToArray(id, value2, position) {
113
+ const output = {
114
+ id,
115
+ value: addToContextArray(value2, position),
116
+ position
117
+ };
118
+ if (!arrayQueue[id]) {
119
+ arrayQueue[id] = [output];
120
+ } else {
121
+ arrayQueue[id].push(output);
122
+ }
123
+ },
124
+ runArrayQueue() {
125
+ Object.keys(arrayQueue).forEach((key) => {
126
+ arrayQueue[key].sort((a, b) => {
127
+ return (a?.position ?? Infinity) - (b.position ?? Infinity);
128
+ });
129
+ for (const item of arrayQueue[key]) {
130
+ this.set(key, item.value, []);
131
+ }
132
+ });
133
+ arrayQueue = {};
134
+ }
135
+ };
136
+ }
137
+ var context = createContext({});
138
+ function addToContextArray(newValue, position) {
139
+ return function(currentValue) {
140
+ if (!currentValue) return [newValue];
141
+ if (typeof position === "number") {
142
+ if (position > currentValue?.length) {
143
+ const output = [...currentValue, ...new Array(position + 1 - currentValue.length)];
144
+ return output.toSpliced(position, 0, newValue);
145
+ }
146
+ if (currentValue?.[position] === void 0) return currentValue.toSpliced(position, 1, newValue);
147
+ return currentValue.toSpliced(position, 0, newValue);
148
+ }
149
+ return [...currentValue, newValue];
150
+ };
151
+ }
152
+
153
+ // src/build/typescript-builder.ts
20
154
  function findDataAttributesAndFunctions(node, sourceFile, foundDataAttributes = [], foundFunctions = []) {
21
155
  if (node.kind === ts.SyntaxKind.JsxAttribute) {
22
156
  const attribute = getAttributeValuePair(node, sourceFile);
@@ -88,18 +222,7 @@ function removeClientScriptInTSXFile(pathName, source) {
88
222
  }
89
223
  if (child.kind === ts.SyntaxKind.ImportDeclaration && child.pos >= clientDataStart) {
90
224
  const text = child.getText(source);
91
- child.forEachChild((child2) => {
92
- if (child2.kind === ts.SyntaxKind.StringLiteral) {
93
- const text2 = child2.getText(source);
94
- const importPath = text2.replace(/[\"\']/g, "");
95
- const isRelativeImport = importPath.startsWith(".") || importPath.startsWith("/");
96
- if (!isRelativeImport) return;
97
- clientImportsToReplace.push({
98
- old: importPath,
99
- new: path.join(path.dirname(pathName), importPath)
100
- });
101
- }
102
- });
225
+ clientImportsToReplace.push(...getImportsToAbsolutePaths(child, source, pathName));
103
226
  clientImportsToHoist.push(text);
104
227
  }
105
228
  });
@@ -115,18 +238,58 @@ function removeClientScriptInTSXFile(pathName, source) {
115
238
  clientDataStart
116
239
  };
117
240
  }
241
+ function getImportsToAbsolutePaths(child, source, pathName) {
242
+ const output = [];
243
+ child.forEachChild((child2) => {
244
+ if (child2.kind === ts.SyntaxKind.StringLiteral) {
245
+ const text = child2.getText(source);
246
+ const importPath = text.replace(/[\"\']/g, "");
247
+ const isRelativeImport = importPath.startsWith(".") || importPath.startsWith("/");
248
+ if (!isRelativeImport) return;
249
+ output.push({
250
+ old: importPath,
251
+ new: path2.join(path2.dirname(pathName), importPath)
252
+ });
253
+ }
254
+ });
255
+ return output;
256
+ }
257
+ function getXpineOnLoadFunction(pathName, source, onLoadFileResult) {
258
+ const value = {
259
+ imports: "",
260
+ fn: ""
261
+ };
262
+ source.forEachChild((child) => {
263
+ if (child.kind == ts.SyntaxKind.ImportDeclaration) {
264
+ let importText = child.getText(source);
265
+ const importOutput = getImportsToAbsolutePaths(child, source, pathName);
266
+ for (const importItem of importOutput) {
267
+ importText = importText.replace(importItem.old, importItem.new);
268
+ }
269
+ value.imports = importText + "\n" + value.imports;
270
+ }
271
+ if ([ts.SyntaxKind.FirstStatement, ts.SyntaxKind.FunctionDeclaration].includes(child.kind)) {
272
+ let text = child.getText(source);
273
+ if (text.includes("xpineOnLoad")) {
274
+ const body = child?.body?.getText(source) || "";
275
+ value.fn = value.fn + "\n" + body ? `(function() ${body})();` : "";
276
+ }
277
+ }
278
+ });
279
+ return value;
280
+ }
281
+ async function triggerXPineOnLoad(noCache = false) {
282
+ context.clear();
283
+ const xpineOnLoad = (await import(path2.join(config.distDir, `./__xpineOnLoad.js${noCache ? `?cache=${Date.now()}` : ""}`)))?.default;
284
+ if (xpineOnLoad) await xpineOnLoad();
285
+ }
118
286
 
119
287
  // src/scripts/build.ts
120
288
  import { globSync } from "glob";
121
289
  import postcss from "postcss";
122
290
  import tailwindPostcss from "@tailwindcss/postcss";
123
291
 
124
- // src/util/get-config.ts
125
- import path2 from "path";
126
-
127
- // src/util/require.ts
128
- import { createRequire } from "module";
129
- var require_default = createRequire(import.meta.url);
292
+ // src/util/paths.ts
130
293
  function getXPineDistDir() {
131
294
  const dir = import.meta.dirname;
132
295
  const splitDir = dir.split("/xpine/dist");
@@ -137,68 +300,6 @@ function getXPineDistDir() {
137
300
  return splitDir[0] + "/xpine/dist";
138
301
  }
139
302
 
140
- // src/util/get-config.ts
141
- var rootDir = process.cwd();
142
- function fromRoot(pathName) {
143
- if (!pathName) return rootDir;
144
- return path2.join(rootDir, pathName);
145
- }
146
- var userConfig = require_default(path2.join(process.cwd(), "./xpine.config.mjs")).default;
147
- var configDefaults = {
148
- rootDir: fromRoot(),
149
- srcDir: fromRoot("./src"),
150
- distDir: fromRoot("./dist"),
151
- packageJsonPath: fromRoot("package.json"),
152
- // We need to use getters here in the event someone wants to change folders, such as the dist folder
153
- get distPublicDir() {
154
- return path2.join(this.distDir, "./public");
155
- },
156
- get distPublicScriptsDir() {
157
- return path2.join(this.distPublicDir, "./scripts");
158
- },
159
- get distTempFolder() {
160
- return path2.join(this.distDir, "./temp");
161
- },
162
- get clientJSBundlePath() {
163
- return path2.join(this.distPublicScriptsDir, "./app.js");
164
- },
165
- get alpineDataPath() {
166
- return path2.join(this.distTempFolder, "./alpine-data.ts");
167
- },
168
- get serverDistDir() {
169
- return path2.join(this.distDir, "./server");
170
- },
171
- get serverDistAppPath() {
172
- return path2.join(this.serverDistDir, "./app.js");
173
- },
174
- // Important dirs/paths
175
- get pagesDir() {
176
- return path2.join(this.srcDir, "./pages");
177
- },
178
- get distPagesDir() {
179
- return path2.join(this.distDir, "./pages");
180
- },
181
- get publicDir() {
182
- return path2.join(this.srcDir, "./public");
183
- },
184
- get serverDir() {
185
- return path2.join(this.srcDir, "./server");
186
- },
187
- get runDir() {
188
- return path2.join(this.serverDir, "./run");
189
- },
190
- get serverAppPath() {
191
- return path2.join(this.serverDir, "./app.ts");
192
- },
193
- get globalCSSFile() {
194
- return path2.join(this.publicDir, "./styles/global.css");
195
- }
196
- };
197
- var config = {
198
- ...configDefaults,
199
- ...userConfig
200
- };
201
-
202
303
  // src/util/postcss/remove-layers.ts
203
304
  var plugin = (opts = {}) => {
204
305
  return {
@@ -272,13 +373,16 @@ function transformTSXFiles(componentData, pageConfigFiles) {
272
373
  ts2.ScriptTarget.Latest
273
374
  );
274
375
  const cleanedContent = removeClientScriptInTSXFile(args.path, source);
275
- const htmlImportStart = "import { html } from 'xpine';\n";
276
- const newContent = `${htmlImportStart}${cleanedContent.content}`;
376
+ const htmlImportStart = [
377
+ "import { html } from 'xpine';"
378
+ ];
379
+ const newContent = `${htmlImportStart.join("\n")}${cleanedContent.content}`;
277
380
  componentData.push({
278
381
  ...args,
279
382
  contents: `${htmlImportStart}${cleanedContent.fullContent}`,
280
383
  clientContent: cleanedContent.clientContent,
281
- configFiles: isAConfigFile(args?.path) ? null : getConfigFiles(args.path, pageConfigFiles)
384
+ configFiles: isAConfigFile(args?.path) ? null : getConfigFiles(args.path, pageConfigFiles),
385
+ source
282
386
  });
283
387
  return {
284
388
  contents: newContent,
@@ -348,7 +452,10 @@ var extensions = [".ts", ".tsx"];
348
452
  var packageJson = JSON.parse(fs5.readFileSync(config.packageJsonPath, "utf-8"));
349
453
  var allPackages = Object.keys(packageJson.devDependencies).concat(Object.keys(packageJson.dependencies));
350
454
  var xpineDistDir = getXPineDistDir();
351
- async function buildApp(isDev = false, removePreviousBuild = false) {
455
+ async function buildApp(args) {
456
+ const isDev = args?.isDev || false;
457
+ const removePreviousBuild = args?.removePreviousBuild || false;
458
+ const disableTailwind = args?.disableTailwind || false;
352
459
  try {
353
460
  if (removePreviousBuild) fs5.removeSync(config.distDir);
354
461
  const srcDirFiles = globSync(config.srcDir + "/**/*.{js,ts,tsx,jsx}");
@@ -356,9 +463,12 @@ async function buildApp(isDev = false, removePreviousBuild = false) {
356
463
  const alpineDataFile = await buildAlpineDataFile(componentData, dataFiles);
357
464
  await buildClientSideFiles([alpineDataFile], isDev);
358
465
  fs5.removeSync(config.distTempFolder);
359
- await buildCSS();
466
+ await buildCSS(disableTailwind);
360
467
  await buildPublicFolderSymlinks();
468
+ await buildOnLoadFile(componentData, isDev);
469
+ if (!isDev) await triggerXPineOnLoad();
361
470
  if (!isDev) await buildFilesWithConfigs(componentData);
471
+ if (!isDev) context.clear();
362
472
  } catch (err) {
363
473
  console.error("Build failed");
364
474
  console.error(err);
@@ -452,12 +562,7 @@ async function buildAlpineDataFile(componentData, dataFiles) {
452
562
  };
453
563
  const componentsAndDataFiles = componentData.concat(dataFiles);
454
564
  for (const component of componentsAndDataFiles) {
455
- const sourceFile = ts3.createSourceFile(
456
- component.path,
457
- component.contents,
458
- ts3.ScriptTarget.Latest
459
- );
460
- const dataFunctionResult = findDataAttributesAndFunctions(sourceFile, sourceFile);
565
+ const dataFunctionResult = findDataAttributesAndFunctions(component.source, component.source);
461
566
  dataFunctionResults.foundDataAttributes.push(...dataFunctionResult.foundDataAttributes);
462
567
  const foundFunctionsWithPath = dataFunctionResult.foundFunctions.map((item) => {
463
568
  return {
@@ -481,11 +586,11 @@ async function buildAlpineDataFile(componentData, dataFiles) {
481
586
  fs5.writeFileSync(config.alpineDataPath, result);
482
587
  return config.alpineDataPath;
483
588
  }
484
- async function buildCSS() {
589
+ async function buildCSS(disableTailwind) {
485
590
  const cssFiles = globSync(config.srcDir + "/**/*.css");
486
591
  for (const file of cssFiles) {
487
592
  const fileContents = fs5.readFileSync(file, "utf-8");
488
- const result = await postcss([tailwindPostcss(), remove_layers_default()]).process(fileContents, { from: file });
593
+ const result = disableTailwind ? fileContents : await postcss([tailwindPostcss(), remove_layers_default()]).process(fileContents, { from: file });
489
594
  const newPath = file.replace(config.srcDir, config.distDir);
490
595
  fs5.ensureFileSync(newPath);
491
596
  fs5.writeFileSync(newPath, result.css);
@@ -547,6 +652,7 @@ async function buildStaticFiles(config2, component, componentImport, builtCompon
547
652
  }
548
653
  const componentDynamicPaths = getComponentDynamicPaths(componentFileName);
549
654
  const componentFn = componentImport.default;
655
+ if (componentImport?.onInit) await componentImport.onInit();
550
656
  const outputPath = componentDynamicPaths?.length ? componentDynamicPaths.reduce((total, current) => {
551
657
  return total.replace(`/[${current}]`, "");
552
658
  }, path5.dirname(builtComponentPath)) : path5.dirname(builtComponentPath);
@@ -596,6 +702,53 @@ function getComponentDynamicPaths(componentPath) {
596
702
  }
597
703
  return output;
598
704
  }
705
+ async function buildOnLoadFile(componentData, isDev) {
706
+ const onLoadFiles = [];
707
+ const onLoadFileResult = {
708
+ imports: "",
709
+ fn: ""
710
+ };
711
+ for (const component of componentData) {
712
+ if (component.contents.includes("xpineOnLoad")) {
713
+ onLoadFiles.push({
714
+ path: sourcePathToDistPath(component.path),
715
+ source: component.source
716
+ });
717
+ }
718
+ }
719
+ onLoadFiles.sort((a, b) => {
720
+ return a.path.localeCompare(b.path);
721
+ });
722
+ for (const file of onLoadFiles) {
723
+ const result = getXpineOnLoadFunction(file.path, file.source, onLoadFileResult);
724
+ onLoadFileResult.fn += result.fn;
725
+ onLoadFileResult.imports += result.imports;
726
+ }
727
+ const output = `
728
+ ${onLoadFileResult.imports}
729
+ import { context } from "xpine";
730
+ export default async function triggerOnLoad() {
731
+ ${onLoadFileResult.fn}
732
+ context.runArrayQueue();
733
+ }
734
+ `;
735
+ const onLoadFilePath = path5.join(config.distDir, "./__xpineOnLoad.ts");
736
+ fs5.writeFileSync(onLoadFilePath, output);
737
+ await build({
738
+ entryPoints: [onLoadFilePath],
739
+ format: "esm",
740
+ platform: "node",
741
+ outdir: config.distDir,
742
+ bundle: true,
743
+ sourcemap: isDev ? "inline" : false,
744
+ external: allPackages,
745
+ jsx: "transform",
746
+ minify: !isDev,
747
+ plugins: [
748
+ addDotJS(allPackages, extensions, isDev)
749
+ ]
750
+ });
751
+ }
599
752
 
600
753
  // src/runDevServer.ts
601
754
  import path7 from "path";
@@ -636,7 +789,7 @@ await setupEnv();
636
789
  async function runDevServer() {
637
790
  process.env.NODE_ENV = "development";
638
791
  const rebuildEmitter = createRebuildEmitter();
639
- await buildApp(true);
792
+ await buildApp({ isDev: true });
640
793
  const startServer = (await import(config.serverDistAppPath + `?cache=${Date.now()}`)).default;
641
794
  let appServer = await startServer();
642
795
  const watcher = chokidar.watch(config.srcDir, {
@@ -651,14 +804,14 @@ async function runDevServer() {
651
804
  rebuildEmitter.emit("rebuild-server");
652
805
  return;
653
806
  }
654
- await buildApp(true);
807
+ await buildApp({ isDev: true });
655
808
  refreshEmitter.emit("refresh");
656
809
  });
657
810
  rebuildEmitter.on("done", async () => {
658
811
  await rebuildServer();
659
812
  });
660
813
  async function rebuildServer() {
661
- await buildApp(true);
814
+ await buildApp({ isDev: true });
662
815
  const startServer2 = (await import(config.serverDistAppPath + `?cache=${Date.now()}`)).default;
663
816
  appServer = await startServer2();
664
817
  }
@@ -0,0 +1,3 @@
1
+ import { ConfigFile } from "../../../types";
2
+ export default function createOnInit(onInit: ConfigFile['onInit']): () => Promise<void>;
3
+ //# sourceMappingURL=onInit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"onInit.d.ts","sourceRoot":"","sources":["../../../../src/util/hooks/onInit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAI5C,MAAM,CAAC,OAAO,UAAU,YAAY,CAAC,MAAM,EAAE,UAAU,CAAC,QAAQ,CAAC,uBAOhE"}
@@ -0,0 +1,2 @@
1
+ export declare function getXPineDistDir(): string;
2
+ //# sourceMappingURL=paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../../src/util/paths.ts"],"names":[],"mappings":"AAAA,wBAAgB,eAAe,WAS9B"}
@@ -1,4 +1,3 @@
1
1
  declare const _default: NodeJS.Require;
2
2
  export default _default;
3
- export declare function getXPineDistDir(): string;
4
3
  //# sourceMappingURL=require.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"require.d.ts","sourceRoot":"","sources":["../../../src/util/require.ts"],"names":[],"mappings":";AAEA,wBAA8C;AAE9C,wBAAgB,eAAe,WAS9B"}
1
+ {"version":3,"file":"require.d.ts","sourceRoot":"","sources":["../../../src/util/require.ts"],"names":[],"mappings":";AAEA,wBAA8C"}
package/dist/types.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { Request, Response } from 'express';
2
+ import ts from 'typescript';
2
3
  export type XPineConfig = {
3
4
  [key: string]: any;
4
5
  };
@@ -37,5 +38,6 @@ export type ComponentData = {
37
38
  contents: string;
38
39
  clientContent: string;
39
40
  configFiles: string[];
41
+ source: ts.SourceFile;
40
42
  };
41
43
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAE5C,MAAM,MAAM,WAAW,GAAG;IACxB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB,CAAA;AAED,MAAM,MAAM,SAAS,GAAG;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAA;AAED,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG;IACpC,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,GAAG,EAAE,aAAa,CAAC;IACnB,QAAQ,EAAE,GAAG,CAAC;IACd,MAAM,EAAE,UAAU,CAAC;IACnB,IAAI,CAAC,EAAE,GAAG,CAAC;CACZ,CAAA;AAED,MAAM,MAAM,UAAU,GAAG;IACvB,WAAW,CAAC,EAAE,OAAO,GAAG,CAAC,MAAM,OAAO,CAAC;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;KAAC,EAAE,CAAC,CAAC,CAAC;IACpE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;IAChD,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,aAAa,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;CAC7C,CAAA;AAED,MAAM,MAAM,SAAS,GAAG;IACtB,GAAG,EAAE,aAAa,CAAC;IACnB,GAAG,EAAE,QAAQ,CAAC;IACd,IAAI,EAAE,GAAG,CAAC;CACX,CAAA;AAED,MAAM,MAAM,QAAQ,GAAG;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd,CAAA;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB,CAAA"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EAAE,MAAM,YAAY,CAAC;AAE5B,MAAM,MAAM,WAAW,GAAG;IACxB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB,CAAA;AAED,MAAM,MAAM,SAAS,GAAG;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAA;AAED,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG;IACpC,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,GAAG,EAAE,aAAa,CAAC;IACnB,QAAQ,EAAE,GAAG,CAAC;IACd,MAAM,EAAE,UAAU,CAAC;IACnB,IAAI,CAAC,EAAE,GAAG,CAAC;CACZ,CAAA;AAED,MAAM,MAAM,UAAU,GAAG;IACvB,WAAW,CAAC,EAAE,OAAO,GAAG,CAAC,MAAM,OAAO,CAAC;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,EAAE,CAAC,CAAC,CAAC;IACrE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;IAChD,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,aAAa,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;CAC7C,CAAA;AAED,MAAM,MAAM,SAAS,GAAG;IACtB,GAAG,EAAE,aAAa,CAAC;IACnB,GAAG,EAAE,QAAQ,CAAC;IACd,IAAI,EAAE,GAAG,CAAC;CACX,CAAA;AAED,MAAM,MAAM,QAAQ,GAAG;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd,CAAA;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,MAAM,EAAE,EAAE,CAAC,UAAU,CAAC;CACvB,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xpine",
3
- "version": "0.0.24",
3
+ "version": "0.0.27",
4
4
  "main": "dist/index.js",
5
5
  "dependencies": {
6
6
  "@aws-sdk/client-secrets-manager": "^3.758.0",
@@ -33,6 +33,7 @@
33
33
  "test:dev": "cd ./tests && npm run dev",
34
34
  "test:start": "cd ./tests && npm run build && npm start",
35
35
  "test:build": "cd ./tests && npm run build",
36
+ "test:build:dev": "cd ./tests && npm run build:dev",
36
37
  "lint": "npx eslint",
37
38
  "fix": "npx eslint --fix",
38
39
  "release:patch": "npm run build && npm version patch && npm publish"
@@ -45,12 +46,14 @@
45
46
  "type": "module",
46
47
  "devDependencies": {
47
48
  "@eslint/js": "^9.24.0",
49
+ "@tailwindcss/oxide-darwin-arm64": "^4.1.3",
48
50
  "@types/express": "^5.0.0",
49
51
  "@types/node": "^22.13.5",
50
52
  "@types/request-ip": "^0.0.41",
51
53
  "@types/shelljs": "^0.8.15",
52
54
  "@types/yargs": "^17.0.33",
53
55
  "axios": "^1.8.4",
56
+ "lightningcss-darwin-arm64": "^1.29.3",
54
57
  "typescript-eslint": "^8.29.0"
55
58
  }
56
59
  }
package/types.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { Request, Response } from 'express';
2
+ import ts from 'typescript';
2
3
 
3
4
  export type XPineConfig = {
4
5
  [key: string]: any;
@@ -22,7 +23,7 @@ export type WrapperProps = {
22
23
  }
23
24
 
24
25
  export type ConfigFile = {
25
- staticPaths?: boolean | (() => Promise<{ [key: string]: string}[]>);
26
+ staticPaths?: boolean | (() => Promise<{ [key: string]: string }[]>);
26
27
  wrapper?: (props: WrapperProps) => Promise<any>;
27
28
  data?: (req: ServerRequest) => Promise<any>;
28
29
  }
@@ -43,4 +44,5 @@ export type ComponentData = {
43
44
  contents: string;
44
45
  clientContent: string;
45
46
  configFiles: string[];
47
+ source: ts.SourceFile;
46
48
  }
@@ -1,14 +0,0 @@
1
- import { test, expect } from '@playwright/test';
2
- import { url } from '../playwright.config';
3
-
4
- test('pathD button changes color on button click', async ({ page }) => {
5
- await page.goto(url + '/my-path-a2/my-path-b2/my-path-c2/2');
6
- const button = page.getByTestId('path-d-button');
7
- const initialStyle = await button.getAttribute('style');
8
- expect(initialStyle).toEqual('background-color: red');
9
- await test.step('click button', async () => {
10
- await button.click();
11
- const newStyle = await button.getAttribute('style');
12
- expect(newStyle).toEqual('background-color: blue');
13
- });
14
- });
@@ -1,73 +0,0 @@
1
- import { test, expect } from '@playwright/test';
2
- import { config } from 'xpine';
3
- import fs from 'fs-extra';
4
- import path from 'path';
5
- import { url } from '../playwright.config';
6
-
7
- test('app builds', async ({ page }) => {
8
- await page.goto(url);
9
- await expect(page.getByTestId('hello-world')).toHaveText('Hello world');
10
- });
11
-
12
- test('home page uses same file wrapper', async ({ page }) => {
13
- await page.goto(url);
14
- await expect(page.getByTestId('home-page-wrapper')).toBeAttached();
15
- expect(await page.getByTestId('base-config').count()).toEqual(0);
16
- const title = await page.title();
17
- expect(title).toEqual('Home page');
18
- });
19
-
20
- test('same dir +config uses config', async ({ page }) => {
21
- await page.goto(url + '/with-same-dir-wrapper');
22
- await expect(page.getByTestId('base-config')).toBeAttached();
23
- const title = await page.title();
24
- expect(title).toEqual('Default title');
25
- });
26
-
27
- test('dynamic paths with data in +config - path c', async ({ page }) => {
28
- const result = await page.goto(url + '/my-path-a/my-path-b/1');
29
- await expect(page.getByTestId('path-c-data')).toHaveText('sunt aut facere repellat provident occaecati excepturi optio reprehenderit');
30
- await expect(page.getByTestId('path-c-patha')).toHaveText('my-path-a');
31
- await expect(page.getByTestId('path-c-pathb')).toHaveText('my-path-b');
32
- await expect(page.getByTestId('base-config')).toBeAttached();
33
- const body = (await result.body()).toString();
34
- expect(body).toContain('<!-- static -->');
35
- });
36
-
37
- test('dynamic inner paths with config in the component - path d', async ({ page }) => {
38
- const result = await page.goto(url + '/my-path-a2/my-path-b2/my-path-c2/2');
39
- await expect(page.getByTestId('path-d-data')).toHaveText('qui est esse');
40
- await expect(page.getByTestId('path-d-patha')).toHaveText('my-path-a2');
41
- await expect(page.getByTestId('path-d-pathb')).toHaveText('my-path-b2');
42
- await expect(page.getByTestId('path-d-pathc')).toHaveText('my-path-c2');
43
- await expect(page.getByTestId('base-config')).toBeAttached();
44
- const body = (await result.body()).toString();
45
- expect(body).toContain('<!-- static -->');
46
- });
47
-
48
- test('static paths exist for dynamic page', async () => {
49
- expect(fs.existsSync(path.join(config.distDir, './pages/my-path-a2/my-path-b2/my-path-c2/2/index.html'))).toEqual(true);
50
- });
51
-
52
- test('boolean static path', async ({ page }) => {
53
- const result = await page.goto(url + '/boolean-static-path');
54
- const body = (await result.body()).toString();
55
- expect(body).toContain('<!-- static -->');
56
-
57
- expect(fs.existsSync(path.join(config.distDir, './pages/boolean-static-path/index.html'))).toEqual(true);
58
- });
59
-
60
- test('inner static path override', async ({ page }) => {
61
- expect(fs.existsSync(path.join(config.distDir, './pages/base-static-path/index.html'))).toEqual(true);
62
- expect(fs.existsSync(path.join(config.distDir, './pages/base-static-path/non-static-path/index.html'))).toEqual(false);
63
-
64
- const staticResult = await page.goto(url + '/base-static-path');
65
- await expect(page.getByTestId('base-static-path')).toHaveText('My title');
66
- const staticBody = (await staticResult.body()).toString();
67
- expect(staticBody).toContain('<!-- static -->');
68
-
69
- const nonStaticResult = await page.goto(url + '/base-static-path/non-static-path');
70
- await expect(page.getByTestId('non-static-path')).toHaveText('My title');
71
- const nonStaticBody = (await nonStaticResult.body()).toString();
72
- expect(nonStaticBody).not.toContain('<!-- static -->');
73
- });
@@ -1,23 +0,0 @@
1
- import { test, expect } from '@playwright/test';
2
- import { url } from '../playwright.config';
3
-
4
-
5
- test('sticky nav creates request for page contents and does not reload page', async ({ page }) => {
6
- await page.goto(url);
7
- const link = page.getByTestId('navbar-boolean-static-path');
8
- const navbarNow = await page.getByTestId('navbar-now').getAttribute('data-now');
9
- await link.click();
10
- await page.waitForURL('**/boolean-static-path');
11
- const newNavbarNow = await page.getByTestId('navbar-now').getAttribute('data-now');
12
- expect(navbarNow).toEqual(newNavbarNow);
13
- });
14
-
15
- test('non-spa request for page contents reloads page', async ({ page }) => {
16
- await page.goto(url);
17
- const link = page.getByTestId('navbar-non-static-path-non-spa');
18
- const navbarNow = await page.getByTestId('navbar-now').getAttribute('data-now');
19
- await link.click();
20
- await page.waitForURL('**/base-static-path/non-static-path');
21
- const newNavbarNow = await page.getByTestId('navbar-now').getAttribute('data-now');
22
- expect(navbarNow).not.toEqual(newNavbarNow);
23
- });