@sealcode/sealgen 0.16.3 → 0.17.1

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/.eslintrc.cjs CHANGED
@@ -20,6 +20,7 @@ module.exports = {
20
20
  "@typescript-eslint/require-await": 0,
21
21
  "no-await-in-loop": 2,
22
22
  "@typescript-eslint/no-unused-vars": ["warn", { args: "none", "varsIgnorePattern": "^_", }],
23
+ "@typescript-eslint/no-this-alias": 0
23
24
  },
24
25
  settings: { jsdoc: { mode: "typescript" } },
25
26
  overrides: [
@@ -9,7 +9,7 @@ export declare class CSSClump {
9
9
  getEntrypointPath(): string;
10
10
  makeEntrypoint(): Promise<void>;
11
11
  static assignFileToClumps(file_path: string): string[];
12
- static findCSSClumps(project_dir: string): Promise<CSSClump[]>;
12
+ static findCSSClumps(project_dir: string, style_dirs: string[]): Promise<CSSClump[]>;
13
13
  }
14
14
  export declare class CSSBuilder extends Builder {
15
15
  getName(): string;
@@ -1,10 +1,11 @@
1
1
  export declare abstract class Builder {
2
2
  project_dir: string;
3
+ style_dirs: string[];
3
4
  abstract ownsFile(file_path: string): boolean;
4
5
  abstract getName(): string;
5
6
  abstract _build(): Promise<void>;
6
7
  abstract dispose(): Promise<void>;
7
- constructor(project_dir: string);
8
+ constructor(project_dir: string, style_dirs: string[]);
8
9
  ongoing_build: Promise<void> | null;
9
10
  build(notifier?: (message: string) => void): Promise<void>;
10
11
  }
@@ -21,6 +22,10 @@ export declare class BackendTSBuilder extends Builder {
21
22
  _build(): Promise<void>;
22
23
  }
23
24
  export declare class FrontendTSBuilder extends Builder {
25
+ project_dir: string;
26
+ style_dirs: string[];
27
+ controller_dirs: string[];
28
+ constructor(project_dir: string, style_dirs: string[], controller_dirs: string[]);
24
29
  getName(): string;
25
30
  ownsFile(file_path: string): boolean;
26
31
  dispose(): Promise<void>;
@@ -1,5 +1,5 @@
1
1
  import { PluginBuild } from "esbuild";
2
- export declare const rewrite_asset_imports_plugin: {
2
+ export declare const rewrite_asset_imports_plugin: (project_dir: string) => {
3
3
  name: string;
4
4
  setup(build: PluginBuild): void;
5
5
  };
@@ -1 +1 @@
1
- export declare function generateStimulusControllers(): Promise<void>;
1
+ export declare function generateStimulusControllers(controller_dirs: string[]): Promise<void>;
package/lib/CSSBuilder.js CHANGED
@@ -89,9 +89,10 @@ class CSSClump {
89
89
  }
90
90
  return segments;
91
91
  }
92
- static async findCSSClumps(project_dir) {
92
+ static async findCSSClumps(project_dir, style_dirs) {
93
93
  const clumps = {};
94
- const all_files = await walkDir(resolve(project_dir, "src"));
94
+ const dirs_to_scan = [resolve(project_dir, "src"), ...style_dirs];
95
+ const all_files = (await Promise.all(dirs_to_scan.map(walkDir))).flat();
95
96
  for (const file of all_files) {
96
97
  if (!file.endsWith(".css"))
97
98
  continue;
@@ -125,10 +126,9 @@ class CSSBuilder extends Builder {
125
126
  (rel_path) => fs.unlink(resolve(this.project_dir, rel_path))
126
127
  )
127
128
  );
128
- const clumps = await CSSClump.findCSSClumps(this.project_dir);
129
- console.log(
130
- "clumps!",
131
- clumps.map((c) => c.name)
129
+ const clumps = await CSSClump.findCSSClumps(
130
+ this.project_dir,
131
+ this.style_dirs
132
132
  );
133
133
  await Promise.all(clumps.map((clump) => clump.build()));
134
134
  } catch (e) {
package/lib/build.js CHANGED
@@ -2,6 +2,7 @@ import { promises as fs } from "fs";
2
2
  import * as chokidar from "chokidar";
3
3
  import { make_notifier } from "./notifier.js";
4
4
  import getPort from "get-port";
5
+ import { resolve } from "node:path";
5
6
  import _locreq from "locreq";
6
7
  import {
7
8
  BackendTSBuilder,
@@ -9,6 +10,7 @@ import {
9
10
  FrontendTSBuilder
10
11
  } from "./builder.js";
11
12
  import { CSSBuilder } from "./CSSBuilder.js";
13
+ import { hasShape, predicates } from "@sealcode/ts-predicates";
12
14
  const target_locreq = _locreq(process.cwd());
13
15
  async function get_notifier_port() {
14
16
  return getPort({ port: 4e3 });
@@ -23,12 +25,58 @@ async function write_notifier_config(watch, port) {
23
25
  JSON.stringify(config)
24
26
  );
25
27
  }
28
+ const package_json_shape = {
29
+ sealgen: predicates.maybe(
30
+ predicates.shape({
31
+ styleDirs: predicates.maybe(predicates.array(predicates.string)),
32
+ controllerDirs: predicates.maybe(
33
+ predicates.array(predicates.string)
34
+ ),
35
+ copyToPublic: predicates.maybe(
36
+ predicates.array(
37
+ predicates.shape({
38
+ from: predicates.string,
39
+ to: predicates.string
40
+ })
41
+ )
42
+ )
43
+ })
44
+ )
45
+ };
26
46
  async function build(watch) {
27
47
  const project_dir = target_locreq.resolve("");
28
- const fonts_builder = new FontsBuilder(project_dir);
29
- const backend_ts_builder = new BackendTSBuilder(project_dir);
30
- const frontend_ts_builder = new FrontendTSBuilder(project_dir);
31
- const css_builder = new CSSBuilder(project_dir);
48
+ const package_json = JSON.parse(
49
+ await fs.readFile(resolve(project_dir, "package.json"), "utf-8")
50
+ );
51
+ if (!hasShape(package_json_shape, package_json)) {
52
+ throw new Error("Misshaped package.json props");
53
+ }
54
+ const style_dirs = package_json.sealgen?.styleDirs || [];
55
+ const controller_dirs = package_json.sealgen?.controllerDirs || [];
56
+ const copy_to_public = package_json.sealgen?.copyToPublic || [];
57
+ await Promise.all(
58
+ copy_to_public.map(async ({ from, to }) => {
59
+ try {
60
+ await fs.stat(resolve(project_dir, "public", to));
61
+ } catch (e) {
62
+ await fs.mkdir(resolve(project_dir, "public", to, "../"), {
63
+ recursive: true
64
+ });
65
+ await fs.symlink(
66
+ resolve(project_dir, from),
67
+ resolve(project_dir, "public", to)
68
+ );
69
+ }
70
+ })
71
+ );
72
+ const fonts_builder = new FontsBuilder(project_dir, style_dirs);
73
+ const backend_ts_builder = new BackendTSBuilder(project_dir, style_dirs);
74
+ const frontend_ts_builder = new FrontendTSBuilder(
75
+ project_dir,
76
+ style_dirs,
77
+ controller_dirs
78
+ );
79
+ const css_builder = new CSSBuilder(project_dir, style_dirs);
32
80
  const builders = [
33
81
  fonts_builder,
34
82
  backend_ts_builder,
package/lib/builder.js CHANGED
@@ -11,8 +11,9 @@ import { generateStimulusControllers } from "./generate-stimulus.js";
11
11
  import { FONTS_CONFIG_PATH, getFonts } from "./get-fonts.js";
12
12
  import { relative } from "node:path";
13
13
  class Builder {
14
- constructor(project_dir) {
14
+ constructor(project_dir, style_dirs) {
15
15
  this.project_dir = project_dir;
16
+ this.style_dirs = style_dirs;
16
17
  this.ongoing_build = null;
17
18
  }
18
19
  build(notifier) {
@@ -77,7 +78,10 @@ class BackendTSBuilder extends Builder {
77
78
  loader: Object.fromEntries(
78
79
  embeddable_file_extensions.map((ext) => ["." + ext, "js"])
79
80
  ),
80
- plugins: [rewrite_asset_imports_plugin, load_assets_plugin],
81
+ plugins: [
82
+ rewrite_asset_imports_plugin(this.project_dir),
83
+ load_assets_plugin
84
+ ],
81
85
  metafile: true
82
86
  });
83
87
  await fs.writeFile(
@@ -87,6 +91,12 @@ class BackendTSBuilder extends Builder {
87
91
  }
88
92
  }
89
93
  class FrontendTSBuilder extends Builder {
94
+ constructor(project_dir, style_dirs, controller_dirs) {
95
+ super(project_dir, style_dirs);
96
+ this.project_dir = project_dir;
97
+ this.style_dirs = style_dirs;
98
+ this.controller_dirs = controller_dirs;
99
+ }
90
100
  getName() {
91
101
  return "frontend-ts";
92
102
  }
@@ -97,7 +107,7 @@ class FrontendTSBuilder extends Builder {
97
107
  async dispose() {
98
108
  }
99
109
  async _build() {
100
- await generateStimulusControllers();
110
+ await generateStimulusControllers(this.controller_dirs);
101
111
  const { metafile } = await build({
102
112
  entryPoints: ["./src/front/index.ts"],
103
113
  sourcemap: true,
package/lib/cli.js CHANGED
@@ -9,7 +9,6 @@ import { generateRoutes } from "./generate-routes.js";
9
9
  import { makeEnv } from "./make-env.js";
10
10
  import yargs from "yargs/yargs";
11
11
  import { getFonts } from "./get-fonts.js";
12
- import { generateStimulusControllers } from "./generate-stimulus.js";
13
12
  import { addCRUD } from "./add-crud.js";
14
13
  const actions = {
15
14
  "add-collection": addCollection,
@@ -27,8 +26,7 @@ const actions = {
27
26
  },
28
27
  "make-env": makeEnv,
29
28
  "add-component": addJDDComponent,
30
- "get-fonts": getFonts,
31
- "generate-stimulus": generateStimulusControllers
29
+ "get-fonts": getFonts
32
30
  };
33
31
  void async function() {
34
32
  const action = process.argv.at(2);
@@ -1,8 +1,8 @@
1
1
  import { promises as fs } from "fs";
2
- import { extname } from "node:path";
2
+ import { extname, resolve } from "node:path";
3
3
  import { embeddable_file_extensions } from "../embeddable-file-extensions.js";
4
4
  import { removeNamedImports } from "../../remove-named-imports.js";
5
- const rewrite_asset_imports_plugin = {
5
+ const rewrite_asset_imports_plugin = (project_dir) => ({
6
6
  name: "sealgen-rewrite-asset-imports",
7
7
  setup(build) {
8
8
  build.onLoad({ filter: /\.tsx?$/ }, async (args) => {
@@ -13,9 +13,23 @@ const rewrite_asset_imports_plugin = {
13
13
  "gm"
14
14
  );
15
15
  contents = contents.replaceAll(regex_assets, (line) => {
16
- return line.replace(`.${ext}"`, '.js"');
16
+ line = line.replace(`.${ext}"`, '.js"');
17
+ return line;
17
18
  });
18
19
  }
20
+ const regex_import = new RegExp(
21
+ `^import (\\w+|{[^}]+}) from "([^"]+)";`,
22
+ "gm"
23
+ );
24
+ contents = contents.replaceAll(
25
+ regex_import,
26
+ (line, _, original_path) => {
27
+ return line.replace(
28
+ `"src/`,
29
+ `"` + resolve(project_dir, "./dist") + "/"
30
+ );
31
+ }
32
+ );
19
33
  contents = removeNamedImports(contents);
20
34
  return {
21
35
  contents,
@@ -23,7 +37,7 @@ const rewrite_asset_imports_plugin = {
23
37
  };
24
38
  });
25
39
  }
26
- };
40
+ });
27
41
  export {
28
42
  rewrite_asset_imports_plugin
29
43
  };
@@ -6,10 +6,13 @@ import recursive from "recursive-readdir";
6
6
  import path, { dirname } from "path";
7
7
  import { toKebabCase, toPascalCase } from "js-convert-case";
8
8
  const target_locreq = _locreq(process.cwd());
9
- async function generateStimulusControllers() {
9
+ async function generateStimulusControllers(controller_dirs) {
10
10
  const output_file = "src/front/controllers.ts";
11
- const stimulus_search_dir = target_locreq.resolve("src/");
12
- const controller_names = (await recursive(stimulus_search_dir)).filter((c) => c.endsWith(".stimulus.ts")).sort();
11
+ const stimulus_search_dirs = [
12
+ target_locreq.resolve("src/"),
13
+ ...controller_dirs
14
+ ];
15
+ const controller_names = (await Promise.all(stimulus_search_dirs.map((dir) => recursive(dir)))).flat().filter((c) => c.endsWith(".stimulus.ts")).sort();
13
16
  const controller_data = controller_names.map(
14
17
  (p) => "./" + path.relative(target_locreq.resolve(dirname(output_file)), p).replace(/\.[tj]sx?$/, ".js")
15
18
  ).map((relative_path) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sealcode/sealgen",
3
- "version": "0.16.3",
3
+ "version": "0.17.1",
4
4
  "description": "Module to automate adding routes and collections to a sealious application",
5
5
  "main": "lib/index.js",
6
6
  "type": "module",
package/src/CSSBuilder.ts CHANGED
@@ -100,9 +100,13 @@ export class CSSClump {
100
100
  return segments;
101
101
  }
102
102
 
103
- static async findCSSClumps(project_dir: string): Promise<CSSClump[]> {
103
+ static async findCSSClumps(
104
+ project_dir: string,
105
+ style_dirs: string[]
106
+ ): Promise<CSSClump[]> {
104
107
  const clumps: Record<string, CSSClump> = {};
105
- const all_files = await walkDir(resolve(project_dir, "src"));
108
+ const dirs_to_scan = [resolve(project_dir, "src"), ...style_dirs];
109
+ const all_files = (await Promise.all(dirs_to_scan.map(walkDir))).flat();
106
110
  for (const file of all_files) {
107
111
  if (!file.endsWith(".css")) continue;
108
112
  const clump_names = CSSClump.assignFileToClumps(file);
@@ -141,10 +145,9 @@ export class CSSBuilder extends Builder {
141
145
  fs.unlink(resolve(this.project_dir, rel_path))
142
146
  )
143
147
  );
144
- const clumps = await CSSClump.findCSSClumps(this.project_dir);
145
- console.log(
146
- "clumps!",
147
- clumps.map((c) => c.name)
148
+ const clumps = await CSSClump.findCSSClumps(
149
+ this.project_dir,
150
+ this.style_dirs
148
151
  );
149
152
  await Promise.all(clumps.map((clump) => clump.build()));
150
153
  } catch (e) {
package/src/build.ts CHANGED
@@ -2,6 +2,7 @@ import { promises as fs } from "fs";
2
2
  import * as chokidar from "chokidar";
3
3
  import { make_notifier } from "./notifier.js";
4
4
  import getPort from "get-port";
5
+ import { resolve } from "node:path";
5
6
 
6
7
  import _locreq from "locreq";
7
8
 
@@ -11,6 +12,7 @@ import {
11
12
  FrontendTSBuilder,
12
13
  } from "./builder.js";
13
14
  import { CSSBuilder } from "./CSSBuilder.js";
15
+ import { hasShape, predicates } from "@sealcode/ts-predicates";
14
16
  const target_locreq = _locreq(process.cwd());
15
17
 
16
18
  async function get_notifier_port() {
@@ -28,12 +30,61 @@ async function write_notifier_config(watch: boolean, port?: number) {
28
30
  );
29
31
  }
30
32
 
33
+ const package_json_shape = {
34
+ sealgen: predicates.maybe(
35
+ predicates.shape({
36
+ styleDirs: predicates.maybe(predicates.array(predicates.string)),
37
+ controllerDirs: predicates.maybe(
38
+ predicates.array(predicates.string)
39
+ ),
40
+ copyToPublic: predicates.maybe(
41
+ predicates.array(
42
+ predicates.shape({
43
+ from: predicates.string,
44
+ to: predicates.string,
45
+ })
46
+ )
47
+ ),
48
+ })
49
+ ),
50
+ };
51
+
31
52
  async function build(watch: boolean): Promise<void> {
32
53
  const project_dir = target_locreq.resolve("");
33
- const fonts_builder = new FontsBuilder(project_dir);
34
- const backend_ts_builder = new BackendTSBuilder(project_dir);
35
- const frontend_ts_builder = new FrontendTSBuilder(project_dir);
36
- const css_builder = new CSSBuilder(project_dir);
54
+ const package_json = JSON.parse(
55
+ await fs.readFile(resolve(project_dir, "package.json"), "utf-8")
56
+ ) as Record<string, unknown>;
57
+ if (!hasShape(package_json_shape, package_json)) {
58
+ throw new Error("Misshaped package.json props");
59
+ }
60
+ const style_dirs = package_json.sealgen?.styleDirs || [];
61
+ const controller_dirs = package_json.sealgen?.controllerDirs || [];
62
+ const copy_to_public = package_json.sealgen?.copyToPublic || [];
63
+
64
+ await Promise.all(
65
+ copy_to_public.map(async ({ from, to }) => {
66
+ try {
67
+ await fs.stat(resolve(project_dir, "public", to));
68
+ } catch (e) {
69
+ await fs.mkdir(resolve(project_dir, "public", to, "../"), {
70
+ recursive: true,
71
+ });
72
+ await fs.symlink(
73
+ resolve(project_dir, from),
74
+ resolve(project_dir, "public", to)
75
+ );
76
+ }
77
+ })
78
+ );
79
+
80
+ const fonts_builder = new FontsBuilder(project_dir, style_dirs);
81
+ const backend_ts_builder = new BackendTSBuilder(project_dir, style_dirs);
82
+ const frontend_ts_builder = new FrontendTSBuilder(
83
+ project_dir,
84
+ style_dirs,
85
+ controller_dirs
86
+ );
87
+ const css_builder = new CSSBuilder(project_dir, style_dirs);
37
88
  const builders = [
38
89
  fonts_builder,
39
90
  backend_ts_builder,
package/src/builder.ts CHANGED
@@ -9,7 +9,11 @@ import { generateComponents } from "./generate-components.js";
9
9
  import { generateRoutes } from "./generate-routes.js";
10
10
  import { generateStimulusControllers } from "./generate-stimulus.js";
11
11
  import { FONTS_CONFIG_PATH, getFonts } from "./get-fonts.js";
12
- import { relative } from "node:path";
12
+ import { relative, resolve } from "node:path";
13
+ import {
14
+ prepareSingleFileReplaceTscAliasPaths,
15
+ SingleFileReplacer,
16
+ } from "tsc-alias";
13
17
 
14
18
  export abstract class Builder {
15
19
  abstract ownsFile(file_path: string): boolean;
@@ -17,7 +21,7 @@ export abstract class Builder {
17
21
  abstract _build(): Promise<void>;
18
22
  abstract dispose(): Promise<void>;
19
23
 
20
- constructor(public project_dir: string) {}
24
+ constructor(public project_dir: string, public style_dirs: string[]) {}
21
25
 
22
26
  public ongoing_build: Promise<void> | null = null;
23
27
 
@@ -86,6 +90,7 @@ export class BackendTSBuilder extends Builder {
86
90
  )}}`
87
91
  )
88
92
  ).filter((path) => !path.includes(".#"));
93
+
89
94
  const { metafile } = await build({
90
95
  entryPoints,
91
96
  sourcemap: true,
@@ -100,7 +105,10 @@ export class BackendTSBuilder extends Builder {
100
105
  loader: Object.fromEntries(
101
106
  embeddable_file_extensions.map((ext) => ["." + ext, "js"])
102
107
  ),
103
- plugins: [rewrite_asset_imports_plugin, load_assets_plugin],
108
+ plugins: [
109
+ rewrite_asset_imports_plugin(this.project_dir),
110
+ load_assets_plugin,
111
+ ],
104
112
  metafile: true,
105
113
  });
106
114
 
@@ -112,6 +120,14 @@ export class BackendTSBuilder extends Builder {
112
120
  }
113
121
 
114
122
  export class FrontendTSBuilder extends Builder {
123
+ constructor(
124
+ public project_dir: string,
125
+ public style_dirs: string[],
126
+ public controller_dirs: string[]
127
+ ) {
128
+ super(project_dir, style_dirs);
129
+ }
130
+
115
131
  getName(): string {
116
132
  return "frontend-ts";
117
133
  }
@@ -127,7 +143,7 @@ export class FrontendTSBuilder extends Builder {
127
143
  async dispose(): Promise<void> {}
128
144
 
129
145
  async _build(): Promise<void> {
130
- await generateStimulusControllers();
146
+ await generateStimulusControllers(this.controller_dirs);
131
147
  const { metafile } = await build({
132
148
  entryPoints: ["./src/front/index.ts"],
133
149
  sourcemap: true,
package/src/cli.ts CHANGED
@@ -9,7 +9,6 @@ import { generateRoutes } from "./generate-routes.js";
9
9
  import { makeEnv } from "./make-env.js";
10
10
  import yargs from "yargs/yargs";
11
11
  import { getFonts } from "./get-fonts.js";
12
- import { generateStimulusControllers } from "./generate-stimulus.js";
13
12
  import { addCRUD } from "./add-crud.js";
14
13
 
15
14
  const actions: Record<
@@ -34,7 +33,6 @@ const actions: Record<
34
33
  "make-env": makeEnv,
35
34
  "add-component": addJDDComponent,
36
35
  "get-fonts": getFonts,
37
- "generate-stimulus": generateStimulusControllers,
38
36
  };
39
37
 
40
38
  void (async function () {
@@ -1,10 +1,10 @@
1
1
  import { promises as fs } from "fs";
2
- import { extname } from "node:path";
2
+ import { extname, resolve } from "node:path";
3
3
  import { embeddable_file_extensions } from "../embeddable-file-extensions.js";
4
4
  import { removeNamedImports } from "../../remove-named-imports.js";
5
5
  import { PluginBuild } from "esbuild";
6
6
 
7
- export const rewrite_asset_imports_plugin = {
7
+ export const rewrite_asset_imports_plugin = (project_dir: string) => ({
8
8
  name: "sealgen-rewrite-asset-imports",
9
9
  setup(build: PluginBuild) {
10
10
  build.onLoad({ filter: /\.tsx?$/ }, async (args) => {
@@ -15,9 +15,23 @@ export const rewrite_asset_imports_plugin = {
15
15
  "gm"
16
16
  );
17
17
  contents = contents.replaceAll(regex_assets, (line) => {
18
- return line.replace(`.${ext}"`, '.js"');
18
+ line = line.replace(`.${ext}"`, '.js"');
19
+ return line;
19
20
  });
20
21
  }
22
+ const regex_import = new RegExp(
23
+ `^import (\\w+|{[^}]+}) from "([^"]+)";`,
24
+ "gm"
25
+ );
26
+ contents = contents.replaceAll(
27
+ regex_import,
28
+ (line, _: string, original_path: string) => {
29
+ return line.replace(
30
+ `"src/`,
31
+ `"` + resolve(project_dir, "./dist") + "/"
32
+ );
33
+ }
34
+ );
21
35
 
22
36
  contents = removeNamedImports(contents) as string;
23
37
 
@@ -27,4 +41,4 @@ export const rewrite_asset_imports_plugin = {
27
41
  };
28
42
  });
29
43
  },
30
- };
44
+ });
@@ -8,10 +8,18 @@ import { toKebabCase, toPascalCase } from "js-convert-case";
8
8
 
9
9
  const target_locreq = _locreq(process.cwd());
10
10
 
11
- export async function generateStimulusControllers(): Promise<void> {
11
+ export async function generateStimulusControllers(
12
+ controller_dirs: string[]
13
+ ): Promise<void> {
12
14
  const output_file = "src/front/controllers.ts";
13
- const stimulus_search_dir = target_locreq.resolve("src/");
14
- const controller_names = (await recursive(stimulus_search_dir))
15
+ const stimulus_search_dirs = [
16
+ target_locreq.resolve("src/"),
17
+ ...controller_dirs,
18
+ ];
19
+ const controller_names = (
20
+ await Promise.all(stimulus_search_dirs.map((dir) => recursive(dir)))
21
+ )
22
+ .flat()
15
23
  .filter((c) => c.endsWith(".stimulus.ts"))
16
24
  .sort();
17
25
  const controller_data = controller_names