akanjs 2.0.0-rc.0 → 2.0.0-rc.2
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/cli/index.js +43 -9
- package/cli/templates/app/env/env.server.debug.ts.template +1 -4
- package/cli/templates/workspaceRoot/.env.template +2 -8
- package/cli/templates/workspaceRoot/biome.json.template +175 -0
- package/cli/templates/workspaceRoot/bunfig.toml +4 -0
- package/cli/templates/workspaceRoot/package.json.template +1 -0
- package/devkit/executors.ts +6 -3
- package/devkit/frontendBuild/clientEntryDiscovery.ts +6 -2
- package/devkit/transforms/barrelAnalyzer.ts +3 -0
- package/devkit/transforms/barrelImportsPlugin.ts +59 -30
- package/package.json +1 -1
- package/cli/templates/app/tsconfig.spec.json.template +0 -7
- package/cli/templates/libRoot/tsconfig.spec.json.template +0 -7
- package/cli/templates/workspaceRoot/.prettierignore.template +0 -10
- package/cli/templates/workspaceRoot/.prettierrc.json.template +0 -6
- package/cli/templates/workspaceRoot/.swcrc.template +0 -9
- package/cli/templates/workspaceRoot/README.md.template +0 -37
package/cli/index.js
CHANGED
|
@@ -9346,7 +9346,7 @@ import {
|
|
|
9346
9346
|
fork,
|
|
9347
9347
|
spawn
|
|
9348
9348
|
} from "child_process";
|
|
9349
|
-
import { mkdir as mkdir2, stat as stat2 } from "fs/promises";
|
|
9349
|
+
import { mkdir as mkdir2, readdir as readDirEntries, stat as stat2 } from "fs/promises";
|
|
9350
9350
|
import path7 from "path";
|
|
9351
9351
|
import chalk4 from "chalk";
|
|
9352
9352
|
|
|
@@ -11074,7 +11074,7 @@ class Executor {
|
|
|
11074
11074
|
const fileContent = await this.#applyTemplateFile({ templatePath: prefixTemplatePath, targetPath: path7.join(basePath2, filename), scanInfo, overwrite }, dict, options);
|
|
11075
11075
|
return fileContent ? [fileContent] : [];
|
|
11076
11076
|
} else {
|
|
11077
|
-
const subdirs = await
|
|
11077
|
+
const subdirs = await readDirEntries(templatePath);
|
|
11078
11078
|
const fileContents = (await Promise.all(subdirs.map(async (subdir) => {
|
|
11079
11079
|
const subpath = path7.join(templatePath, subdir);
|
|
11080
11080
|
if ((await stat2(subpath)).isFile()) {
|
|
@@ -11198,6 +11198,9 @@ class WorkspaceExecutor extends Executor {
|
|
|
11198
11198
|
if (type === "lib" || type === "pkg")
|
|
11199
11199
|
rootTsConfig.compilerOptions.paths[`@${name}`] = [`${type}s/${name}/index.ts`];
|
|
11200
11200
|
rootTsConfig.compilerOptions.paths[`@${name}/*`] = [`${type}s/${name}/*`];
|
|
11201
|
+
rootTsConfig.compilerOptions.paths[`@${type}s/${name}/*`] = [`${type}s/${name}/*`];
|
|
11202
|
+
if (type === "lib" || type === "pkg")
|
|
11203
|
+
rootTsConfig.compilerOptions.paths[`@${type}s/${name}`] = [`${type}s/${name}/index.ts`];
|
|
11201
11204
|
if (rootTsConfig.references) {
|
|
11202
11205
|
if (!rootTsConfig.references.some((ref) => ref.path === `./${type}s/${name}/tsconfig.json`))
|
|
11203
11206
|
rootTsConfig.references.push({ path: `./${type}s/${name}/tsconfig.json` });
|
|
@@ -11207,7 +11210,7 @@ class WorkspaceExecutor extends Executor {
|
|
|
11207
11210
|
}
|
|
11208
11211
|
async unsetTsPaths(type, name) {
|
|
11209
11212
|
const rootTsConfig = await this.readJson("tsconfig.json");
|
|
11210
|
-
const filteredKeys = Object.keys(rootTsConfig.compilerOptions.paths ?? {}).filter((key) => !key.startsWith(`@${name}`));
|
|
11213
|
+
const filteredKeys = Object.keys(rootTsConfig.compilerOptions.paths ?? {}).filter((key) => !key.startsWith(`@${name}`) && !key.startsWith(`@${type}s/${name}`));
|
|
11211
11214
|
rootTsConfig.compilerOptions.paths = Object.fromEntries(filteredKeys.map((key) => [key, rootTsConfig.compilerOptions.paths?.[key] ?? []]));
|
|
11212
11215
|
if (rootTsConfig.references) {
|
|
11213
11216
|
rootTsConfig.references = rootTsConfig.references.filter((ref) => !ref.path.startsWith(`./${type}s/${name}`));
|
|
@@ -12737,6 +12740,8 @@ class BarrelAnalyzer {
|
|
|
12737
12740
|
const rel = path12.relative(pkg.pkgDir, absFile);
|
|
12738
12741
|
if (!rel || rel.startsWith("..") || path12.isAbsolute(rel))
|
|
12739
12742
|
return null;
|
|
12743
|
+
if (pkg.preserveFilePath)
|
|
12744
|
+
return `${pkg.pkgName}/${rel.split(path12.sep).join("/")}`;
|
|
12740
12745
|
const noExt = stripKnownExt(rel);
|
|
12741
12746
|
const tail = collapseIndex(noExt);
|
|
12742
12747
|
if (tail === "")
|
|
@@ -12817,7 +12822,7 @@ var collapseIndex = (relPathNoExt) => {
|
|
|
12817
12822
|
|
|
12818
12823
|
import path13 from "path";
|
|
12819
12824
|
import ts3 from "typescript";
|
|
12820
|
-
var createBarrelImportsPlugin = async (app, { skipPath =
|
|
12825
|
+
var createBarrelImportsPlugin = async (app, { skipPath = defaultSkipPath, pipeAfter } = {}) => {
|
|
12821
12826
|
const akanConfig2 = await app.getConfig();
|
|
12822
12827
|
const barrels = [...new Set(akanConfig2.barrelImports)].filter(Boolean);
|
|
12823
12828
|
const analyzer = new BarrelAnalyzer({
|
|
@@ -12826,7 +12831,9 @@ var createBarrelImportsPlugin = async (app, { skipPath = (p) => p.includes("node
|
|
|
12826
12831
|
return {
|
|
12827
12832
|
name: "barrel-imports",
|
|
12828
12833
|
setup(build) {
|
|
12829
|
-
build.onLoad({
|
|
12834
|
+
build.onLoad({
|
|
12835
|
+
filter: /^(?:(?!.*[\\/]node_modules[\\/]).*|.*[\\/]node_modules[\\/]akanjs[\\/].*)\.(tsx|ts|jsx|js)(\?v=\d+)?$/
|
|
12836
|
+
}, async (args) => {
|
|
12830
12837
|
const realPath = args.path.replace(/\?v=\d+$/, "");
|
|
12831
12838
|
const loader = loaderFor(realPath);
|
|
12832
12839
|
if (skipPath(realPath)) {
|
|
@@ -12936,6 +12943,9 @@ var createTsconfigPackageResolver = async (app) => {
|
|
|
12936
12943
|
};
|
|
12937
12944
|
};
|
|
12938
12945
|
var CANDIDATE_EXTS2 = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
|
|
12946
|
+
var NODE_MODULES_RE = /[\\/]node_modules[\\/]/;
|
|
12947
|
+
var AKANJS_NODE_MODULE_RE = /[\\/]node_modules[\\/]akanjs[\\/]/;
|
|
12948
|
+
var defaultSkipPath = (absPath) => NODE_MODULES_RE.test(absPath) && !AKANJS_NODE_MODULE_RE.test(absPath);
|
|
12939
12949
|
var resolveNodePackageExport = async (workspaceRoot, specifier) => {
|
|
12940
12950
|
const packageName = getPackageName(specifier);
|
|
12941
12951
|
if (!packageName)
|
|
@@ -12947,7 +12957,7 @@ var resolveNodePackageExport = async (workspaceRoot, specifier) => {
|
|
|
12947
12957
|
const pkgDir = path13.dirname(pkgJsonPath);
|
|
12948
12958
|
const pkgJson = JSON.parse(await Bun.file(pkgJsonPath).text());
|
|
12949
12959
|
const subpath = specifier === packageName ? "." : `.${specifier.slice(packageName.length)}`;
|
|
12950
|
-
const exported =
|
|
12960
|
+
const exported = resolvePackageExport(pkgJson.exports, subpath);
|
|
12951
12961
|
const rel = exported ?? (subpath === "." ? pkgJson.module ?? pkgJson.main ?? "index.js" : null);
|
|
12952
12962
|
if (!rel || !rel.startsWith("."))
|
|
12953
12963
|
return null;
|
|
@@ -12955,7 +12965,7 @@ var resolveNodePackageExport = async (workspaceRoot, specifier) => {
|
|
|
12955
12965
|
if (!entryFile)
|
|
12956
12966
|
return null;
|
|
12957
12967
|
const pkgEntryName = specifier;
|
|
12958
|
-
return { pkgName: pkgEntryName, entryFile, pkgDir: path13.dirname(entryFile) };
|
|
12968
|
+
return { pkgName: pkgEntryName, entryFile, pkgDir: path13.dirname(entryFile), preserveFilePath: true };
|
|
12959
12969
|
} catch {
|
|
12960
12970
|
return null;
|
|
12961
12971
|
}
|
|
@@ -12980,6 +12990,27 @@ var resolveExportValue = (value) => {
|
|
|
12980
12990
|
}
|
|
12981
12991
|
return null;
|
|
12982
12992
|
};
|
|
12993
|
+
var resolvePackageExport = (exportsMap, subpath) => {
|
|
12994
|
+
if (!exportsMap)
|
|
12995
|
+
return null;
|
|
12996
|
+
const exact = resolveExportValue(exportsMap[subpath]);
|
|
12997
|
+
if (exact)
|
|
12998
|
+
return exact;
|
|
12999
|
+
for (const [key, value] of Object.entries(exportsMap)) {
|
|
13000
|
+
const starIdx = key.indexOf("*");
|
|
13001
|
+
if (starIdx === -1)
|
|
13002
|
+
continue;
|
|
13003
|
+
const prefix = key.slice(0, starIdx);
|
|
13004
|
+
const suffix = key.slice(starIdx + 1);
|
|
13005
|
+
if (!subpath.startsWith(prefix) || !subpath.endsWith(suffix))
|
|
13006
|
+
continue;
|
|
13007
|
+
const wildcard = subpath.slice(prefix.length, subpath.length - suffix.length);
|
|
13008
|
+
const resolved = resolveExportValue(value);
|
|
13009
|
+
if (resolved)
|
|
13010
|
+
return resolved.replace("*", wildcard);
|
|
13011
|
+
}
|
|
13012
|
+
return null;
|
|
13013
|
+
};
|
|
12983
13014
|
var getPackageName = (specifier) => {
|
|
12984
13015
|
const parts = specifier.split("/");
|
|
12985
13016
|
if (!parts[0])
|
|
@@ -13173,7 +13204,10 @@ var loaderFor = (absPath) => {
|
|
|
13173
13204
|
|
|
13174
13205
|
var USE_CLIENT_RE = /^\s*(?:\/\*[\s\S]*?\*\/\s*|\/\/[^\n]*\n\s*)*["']use client["']/;
|
|
13175
13206
|
var SOURCE_EXTS2 = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
|
|
13207
|
+
var NODE_MODULES_RE2 = /[\\/]node_modules[\\/]/;
|
|
13208
|
+
var AKANJS_NODE_MODULE_RE2 = /[\\/]node_modules[\\/]akanjs[\\/]/;
|
|
13176
13209
|
var NON_SOURCE_EXT_RE2 = /\.(css|scss|sass|less|json|svg|png|jpe?g|webp|gif|avif|ico|woff2?|ttf|otf|mp3|mp4|wav)$/i;
|
|
13210
|
+
var shouldSkipNodeModule = (absPath) => NODE_MODULES_RE2.test(absPath) && !AKANJS_NODE_MODULE_RE2.test(absPath);
|
|
13177
13211
|
|
|
13178
13212
|
class GraphClientEntryDiscovery {
|
|
13179
13213
|
#akanConfig;
|
|
@@ -13310,7 +13344,7 @@ class GraphClientEntryDiscovery {
|
|
|
13310
13344
|
const cached = this.#reachableEntriesCache.get(absPath);
|
|
13311
13345
|
if (cached)
|
|
13312
13346
|
return new Set(cached);
|
|
13313
|
-
if (visiting.has(absPath) || absPath
|
|
13347
|
+
if (visiting.has(absPath) || shouldSkipNodeModule(absPath))
|
|
13314
13348
|
return new Set;
|
|
13315
13349
|
visiting.add(absPath);
|
|
13316
13350
|
const entries = new Set;
|
|
@@ -13333,7 +13367,7 @@ class GraphClientEntryDiscovery {
|
|
|
13333
13367
|
const resolved = await this.#resolveSpecifier(spec, importerDir);
|
|
13334
13368
|
if (!resolved)
|
|
13335
13369
|
continue;
|
|
13336
|
-
if (resolved
|
|
13370
|
+
if (shouldSkipNodeModule(resolved))
|
|
13337
13371
|
continue;
|
|
13338
13372
|
for (const entry of await this.#discoverFromFile(resolved, visiting))
|
|
13339
13373
|
entries.add(entry);
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# organization configuration, no need to change
|
|
2
2
|
AKAN_PUBLIC_REPO_NAME=<%= repoName %>
|
|
3
|
+
|
|
4
|
+
# serve domain, it changes the domain of the server.
|
|
3
5
|
AKAN_PUBLIC_SERVE_DOMAIN="<%= serveDomain %>"
|
|
4
6
|
|
|
5
7
|
# development branch, debug, develop, main, etc. mainly it changes databases.
|
|
@@ -7,14 +9,6 @@ AKAN_PUBLIC_ENV=local
|
|
|
7
9
|
|
|
8
10
|
# local, cloud, edge it changes the connection point of the clients.
|
|
9
11
|
AKAN_PUBLIC_OPERATION_MODE=local
|
|
10
|
-
# hybrid app specific config, will be depreciated in the future
|
|
11
|
-
APP_OPERATION_MODE=local
|
|
12
|
-
|
|
13
|
-
# backend service mode, federation, batch, all
|
|
14
|
-
SERVER_MODE=federation
|
|
15
|
-
|
|
16
|
-
# analyze the bundle size
|
|
17
|
-
ANALYZE=false
|
|
18
12
|
|
|
19
13
|
# log level, debug, info, warn, error
|
|
20
14
|
AKAN_PUBLIC_LOG_LEVEL=debug
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://biomejs.dev/schemas/2.4.4/schema.json",
|
|
3
|
+
"vcs": {
|
|
4
|
+
"enabled": true,
|
|
5
|
+
"clientKind": "git",
|
|
6
|
+
"useIgnoreFile": false
|
|
7
|
+
},
|
|
8
|
+
"files": {
|
|
9
|
+
"includes": [
|
|
10
|
+
"**/*.ts",
|
|
11
|
+
"**/*.tsx",
|
|
12
|
+
"**/*.json",
|
|
13
|
+
"**/*.jsonc",
|
|
14
|
+
"!**/env.client.local.ts",
|
|
15
|
+
"!**/env.client.debug.ts",
|
|
16
|
+
"!**/env.client.develop.ts",
|
|
17
|
+
"!**/env.client.main.ts",
|
|
18
|
+
"!**/env.client.testing.ts",
|
|
19
|
+
"!**/env.server.local.ts",
|
|
20
|
+
"!**/env.server.develop.ts",
|
|
21
|
+
"!**/env.server.main.ts",
|
|
22
|
+
"!**/env.server.testing.ts",
|
|
23
|
+
"!**/env.server.type.ts",
|
|
24
|
+
"!apps/*/lib/cnst.ts",
|
|
25
|
+
"!apps/*/lib/dict.ts",
|
|
26
|
+
"!apps/*/lib/db.ts",
|
|
27
|
+
"!apps/*/lib/srv.ts",
|
|
28
|
+
"!apps/*/lib/st.ts",
|
|
29
|
+
"!apps/*/lib/sig.ts",
|
|
30
|
+
"!apps/*/lib/useClient.ts",
|
|
31
|
+
"!apps/*/lib/useServer.ts",
|
|
32
|
+
"!apps/*/client.ts",
|
|
33
|
+
"!apps/*/server.ts",
|
|
34
|
+
"!apps/*/lib/*/index.tsx",
|
|
35
|
+
"!libs/*/lib/cnst.ts",
|
|
36
|
+
"!libs/*/lib/dict.ts",
|
|
37
|
+
"!libs/*/lib/db.ts",
|
|
38
|
+
"!libs/*/lib/srv.ts",
|
|
39
|
+
"!libs/*/lib/st.ts",
|
|
40
|
+
"!libs/*/lib/sig.ts",
|
|
41
|
+
"!libs/*/lib/useClient.ts",
|
|
42
|
+
"!libs/*/lib/useServer.ts",
|
|
43
|
+
"!libs/*/client.ts",
|
|
44
|
+
"!libs/*/server.ts",
|
|
45
|
+
"!libs/*/index.ts",
|
|
46
|
+
"!libs/*/lib/*/index.tsx",
|
|
47
|
+
"!infra/master/createRecords.ts",
|
|
48
|
+
"!pkgs/contract/env.ts",
|
|
49
|
+
"!!**/node_modules",
|
|
50
|
+
"!!**/dist",
|
|
51
|
+
"!!**/.akan",
|
|
52
|
+
"!!**/dump",
|
|
53
|
+
"!!**/local"
|
|
54
|
+
]
|
|
55
|
+
},
|
|
56
|
+
"formatter": {
|
|
57
|
+
"enabled": true,
|
|
58
|
+
"indentStyle": "space",
|
|
59
|
+
"indentWidth": 2,
|
|
60
|
+
"lineWidth": 120
|
|
61
|
+
},
|
|
62
|
+
"linter": {
|
|
63
|
+
"enabled": true,
|
|
64
|
+
"rules": {
|
|
65
|
+
"recommended": true,
|
|
66
|
+
"suspicious": {
|
|
67
|
+
"noConsole": {
|
|
68
|
+
"level": "error",
|
|
69
|
+
"options": {
|
|
70
|
+
"allow": ["assert", "error", "info", "warn"]
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
"noArrayIndexKey": "off",
|
|
74
|
+
"noShadowRestrictedNames": "off"
|
|
75
|
+
},
|
|
76
|
+
"correctness": {
|
|
77
|
+
"noUnusedFunctionParameters": "off",
|
|
78
|
+
"noUnusedImports": {
|
|
79
|
+
"level": "error",
|
|
80
|
+
"fix": "safe"
|
|
81
|
+
},
|
|
82
|
+
"useParseIntRadix": "off",
|
|
83
|
+
"useExhaustiveDependencies": "off"
|
|
84
|
+
},
|
|
85
|
+
"nursery": {
|
|
86
|
+
"useSortedClasses": {
|
|
87
|
+
"level": "error",
|
|
88
|
+
"fix": "safe",
|
|
89
|
+
"options": {
|
|
90
|
+
"attributes": ["classList"],
|
|
91
|
+
"functions": ["clsx", "cva"]
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
"a11y": "off",
|
|
96
|
+
"complexity": {
|
|
97
|
+
"noStaticOnlyClass": "off"
|
|
98
|
+
},
|
|
99
|
+
"style": {
|
|
100
|
+
"useTemplate": {
|
|
101
|
+
"level": "warn",
|
|
102
|
+
"fix": "safe"
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
"domains": {
|
|
107
|
+
"project": "recommended",
|
|
108
|
+
"react": "recommended",
|
|
109
|
+
"test": "recommended",
|
|
110
|
+
"types": "all"
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
"javascript": {
|
|
114
|
+
"parser": {
|
|
115
|
+
"unsafeParameterDecoratorsEnabled": true
|
|
116
|
+
},
|
|
117
|
+
"formatter": {
|
|
118
|
+
"quoteStyle": "double"
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
"assist": {
|
|
122
|
+
"enabled": true,
|
|
123
|
+
"actions": {
|
|
124
|
+
"source": {
|
|
125
|
+
"organizeImports": "on"
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
"overrides": [
|
|
130
|
+
{
|
|
131
|
+
"includes": ["**/page/**/*.ts", "**/page/**/*.tsx", "**/*.Unit.tsx", "**/*.View.tsx"],
|
|
132
|
+
"plugins": [
|
|
133
|
+
"./node_modules/akanjs/devkit/lint/no-import-client-functions.grit",
|
|
134
|
+
"./node_modules/akanjs/devkit/lint/no-use-client-in-server.grit"
|
|
135
|
+
]
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
"includes": ["**/page/**/*.ts", "**/page/**/*.tsx"],
|
|
139
|
+
"plugins": ["./node_modules/akanjs/devkit/lint/non-scalar-props-restricted.grit"]
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
"includes": ["**/*.constant.ts", "**/*.document.ts", "**/*.service.ts", "**/*.store.ts"],
|
|
143
|
+
"plugins": ["./node_modules/akanjs/devkit/lint/no-js-private-class-method.grit"]
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
"includes": [
|
|
147
|
+
"**/page/**/*.ts",
|
|
148
|
+
"**/page/**/*.tsx",
|
|
149
|
+
"**/index.ts",
|
|
150
|
+
"**/index.tsx",
|
|
151
|
+
"**/cnst.ts",
|
|
152
|
+
"**/db.ts",
|
|
153
|
+
"**/dict.ts",
|
|
154
|
+
"**/option.ts",
|
|
155
|
+
"**/sig.ts",
|
|
156
|
+
"**/srv.ts",
|
|
157
|
+
"**/st.ts",
|
|
158
|
+
"**/*.constant.ts",
|
|
159
|
+
"**/*.dictionary.ts",
|
|
160
|
+
"**/*.document.ts",
|
|
161
|
+
"**/*.service.ts",
|
|
162
|
+
"**/*.signal.ts",
|
|
163
|
+
"**/*.signal.test.ts",
|
|
164
|
+
"**/*.service.test.ts",
|
|
165
|
+
"**/*.store.ts",
|
|
166
|
+
"**/*.Template.tsx",
|
|
167
|
+
"**/*.Unit.tsx",
|
|
168
|
+
"**/*.Util.tsx",
|
|
169
|
+
"**/*.View.tsx",
|
|
170
|
+
"**/*.Zone.tsx"
|
|
171
|
+
],
|
|
172
|
+
"plugins": ["./node_modules/akanjs/devkit/lint/no-import-external-library.grit"]
|
|
173
|
+
}
|
|
174
|
+
]
|
|
175
|
+
}
|
package/devkit/executors.ts
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
type SpawnOptions,
|
|
8
8
|
spawn,
|
|
9
9
|
} from "node:child_process";
|
|
10
|
-
import { mkdir, stat } from "node:fs/promises";
|
|
10
|
+
import { mkdir, readdir as readDirEntries, stat } from "node:fs/promises";
|
|
11
11
|
import path from "node:path";
|
|
12
12
|
import {
|
|
13
13
|
capitalize,
|
|
@@ -455,7 +455,7 @@ export class Executor {
|
|
|
455
455
|
);
|
|
456
456
|
return fileContent ? [fileContent] : ([] as FileContent[]);
|
|
457
457
|
} else {
|
|
458
|
-
const subdirs = await
|
|
458
|
+
const subdirs = await readDirEntries(templatePath);
|
|
459
459
|
const fileContents = (
|
|
460
460
|
await Promise.all(
|
|
461
461
|
subdirs.map(async (subdir) => {
|
|
@@ -615,6 +615,9 @@ export class WorkspaceExecutor extends Executor {
|
|
|
615
615
|
if (type === "lib" || type === "pkg")
|
|
616
616
|
rootTsConfig.compilerOptions.paths[`@${name}`] = [`${type}s/${name}/index.ts`];
|
|
617
617
|
rootTsConfig.compilerOptions.paths[`@${name}/*`] = [`${type}s/${name}/*`];
|
|
618
|
+
rootTsConfig.compilerOptions.paths[`@${type}s/${name}/*`] = [`${type}s/${name}/*`];
|
|
619
|
+
if (type === "lib" || type === "pkg")
|
|
620
|
+
rootTsConfig.compilerOptions.paths[`@${type}s/${name}`] = [`${type}s/${name}/index.ts`];
|
|
618
621
|
if (rootTsConfig.references) {
|
|
619
622
|
if (!rootTsConfig.references.some((ref) => ref.path === `./${type}s/${name}/tsconfig.json`))
|
|
620
623
|
rootTsConfig.references.push({ path: `./${type}s/${name}/tsconfig.json` });
|
|
@@ -625,7 +628,7 @@ export class WorkspaceExecutor extends Executor {
|
|
|
625
628
|
async unsetTsPaths(type: "app" | "lib" | "pkg", name: string) {
|
|
626
629
|
const rootTsConfig = (await this.readJson("tsconfig.json")) as TsConfigJson;
|
|
627
630
|
const filteredKeys = Object.keys(rootTsConfig.compilerOptions.paths ?? {}).filter(
|
|
628
|
-
(key) => !key.startsWith(`@${name}`),
|
|
631
|
+
(key) => !key.startsWith(`@${name}`) && !key.startsWith(`@${type}s/${name}`),
|
|
629
632
|
);
|
|
630
633
|
rootTsConfig.compilerOptions.paths = Object.fromEntries(
|
|
631
634
|
filteredKeys.map((key) => [key, rootTsConfig.compilerOptions.paths?.[key] ?? []]),
|
|
@@ -6,10 +6,14 @@ import type { AkanConfig, ClientEntryDiscovery, ScannedImport } from "./clientBu
|
|
|
6
6
|
|
|
7
7
|
const USE_CLIENT_RE = /^\s*(?:\/\*[\s\S]*?\*\/\s*|\/\/[^\n]*\n\s*)*["']use client["']/;
|
|
8
8
|
const SOURCE_EXTS = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
|
|
9
|
+
const NODE_MODULES_RE = /[\\/]node_modules[\\/]/;
|
|
10
|
+
const AKANJS_NODE_MODULE_RE = /[\\/]node_modules[\\/]akanjs[\\/]/;
|
|
9
11
|
|
|
10
12
|
const NON_SOURCE_EXT_RE = /\.(css|scss|sass|less|json|svg|png|jpe?g|webp|gif|avif|ico|woff2?|ttf|otf|mp3|mp4|wav)$/i;
|
|
11
13
|
type PackageResolver = Awaited<ReturnType<typeof createTsconfigPackageResolver>>;
|
|
12
14
|
|
|
15
|
+
const shouldSkipNodeModule = (absPath: string) => NODE_MODULES_RE.test(absPath) && !AKANJS_NODE_MODULE_RE.test(absPath);
|
|
16
|
+
|
|
13
17
|
/**
|
|
14
18
|
* Graph-based `"use client"` discovery, seeded from an explicit file list.
|
|
15
19
|
*
|
|
@@ -156,7 +160,7 @@ export class GraphClientEntryDiscovery implements ClientEntryDiscovery {
|
|
|
156
160
|
const absPath = path.resolve(file);
|
|
157
161
|
const cached = this.#reachableEntriesCache.get(absPath);
|
|
158
162
|
if (cached) return new Set(cached);
|
|
159
|
-
if (visiting.has(absPath) || absPath
|
|
163
|
+
if (visiting.has(absPath) || shouldSkipNodeModule(absPath)) return new Set();
|
|
160
164
|
|
|
161
165
|
visiting.add(absPath);
|
|
162
166
|
const entries = new Set<string>();
|
|
@@ -177,7 +181,7 @@ export class GraphClientEntryDiscovery implements ClientEntryDiscovery {
|
|
|
177
181
|
if (NON_SOURCE_EXT_RE.test(spec)) continue;
|
|
178
182
|
const resolved = await this.#resolveSpecifier(spec, importerDir);
|
|
179
183
|
if (!resolved) continue;
|
|
180
|
-
if (resolved
|
|
184
|
+
if (shouldSkipNodeModule(resolved)) continue;
|
|
181
185
|
for (const entry of await this.#discoverFromFile(resolved, visiting)) entries.add(entry);
|
|
182
186
|
}
|
|
183
187
|
|
|
@@ -17,6 +17,8 @@ export interface PackageEntry {
|
|
|
17
17
|
entryFile: string;
|
|
18
18
|
/** Absolute directory used as the base for subpath computation. Typically dirname(entryFile). */
|
|
19
19
|
pkgDir: string;
|
|
20
|
+
/** Preserve concrete file paths for package exports that do not support extensionless deep imports. */
|
|
21
|
+
preserveFilePath?: boolean;
|
|
20
22
|
}
|
|
21
23
|
|
|
22
24
|
export interface BarrelAnalyzerOptions {
|
|
@@ -162,6 +164,7 @@ export class BarrelAnalyzer {
|
|
|
162
164
|
#subpathFor(pkg: PackageEntry, absFile: string): string | null {
|
|
163
165
|
const rel = path.relative(pkg.pkgDir, absFile);
|
|
164
166
|
if (!rel || rel.startsWith("..") || path.isAbsolute(rel)) return null;
|
|
167
|
+
if (pkg.preserveFilePath) return `${pkg.pkgName}/${rel.split(path.sep).join("/")}`;
|
|
165
168
|
const noExt = stripKnownExt(rel);
|
|
166
169
|
|
|
167
170
|
const tail = collapseIndex(noExt);
|
|
@@ -19,7 +19,7 @@ export interface BarrelImportsPluginOptions {
|
|
|
19
19
|
|
|
20
20
|
export const createBarrelImportsPlugin = async (
|
|
21
21
|
app: App,
|
|
22
|
-
{ skipPath =
|
|
22
|
+
{ skipPath = defaultSkipPath, pipeAfter }: BarrelImportsPluginOptions = {},
|
|
23
23
|
): Promise<BunPlugin> => {
|
|
24
24
|
const akanConfig = await app.getConfig();
|
|
25
25
|
const barrels = [...new Set(akanConfig.barrelImports)].filter(Boolean);
|
|
@@ -31,40 +31,46 @@ export const createBarrelImportsPlugin = async (
|
|
|
31
31
|
name: "barrel-imports",
|
|
32
32
|
setup(build) {
|
|
33
33
|
|
|
34
|
-
build.onLoad(
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
34
|
+
build.onLoad(
|
|
35
|
+
{
|
|
36
|
+
filter:
|
|
37
|
+
/^(?:(?!.*[\\/]node_modules[\\/]).*|.*[\\/]node_modules[\\/]akanjs[\\/].*)\.(tsx|ts|jsx|js)(\?v=\d+)?$/,
|
|
38
|
+
},
|
|
39
|
+
async (args) => {
|
|
40
|
+
const realPath = args.path.replace(/\?v=\d+$/, "");
|
|
41
|
+
const loader = loaderFor(realPath);
|
|
42
|
+
if (skipPath(realPath)) {
|
|
43
|
+
const raw = await Bun.file(realPath).text();
|
|
44
|
+
return { contents: raw, loader };
|
|
45
|
+
}
|
|
41
46
|
|
|
42
|
-
|
|
47
|
+
let source = await Bun.file(realPath).text();
|
|
43
48
|
|
|
44
|
-
|
|
49
|
+
const hasMacroAttr = MACRO_ATTR_RE.test(source);
|
|
45
50
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
if (!hasMacroAttr && barrels.length > 0) {
|
|
52
|
+
|
|
53
|
+
let maybe = false;
|
|
54
|
+
for (const b of barrels) {
|
|
55
|
+
if (source.includes(b)) {
|
|
56
|
+
maybe = true;
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if (maybe) {
|
|
61
|
+
const rewritten = await rewriteBarrelImports(source, barrels, analyzer);
|
|
62
|
+
if (rewritten !== null) source = rewritten;
|
|
53
63
|
}
|
|
54
64
|
}
|
|
55
|
-
if (maybe) {
|
|
56
|
-
const rewritten = await rewriteBarrelImports(source, barrels, analyzer);
|
|
57
|
-
if (rewritten !== null) source = rewritten;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
65
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
66
|
+
if (pipeAfter) {
|
|
67
|
+
const piped = await pipeAfter(source, { path: realPath });
|
|
68
|
+
if (piped !== null) source = piped;
|
|
69
|
+
}
|
|
65
70
|
|
|
66
|
-
|
|
67
|
-
|
|
71
|
+
return { contents: source, loader };
|
|
72
|
+
},
|
|
73
|
+
);
|
|
68
74
|
},
|
|
69
75
|
};
|
|
70
76
|
};
|
|
@@ -162,6 +168,10 @@ export const createTsconfigPackageResolver = async (
|
|
|
162
168
|
|
|
163
169
|
const CANDIDATE_EXTS = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
|
|
164
170
|
|
|
171
|
+
const NODE_MODULES_RE = /[\\/]node_modules[\\/]/;
|
|
172
|
+
const AKANJS_NODE_MODULE_RE = /[\\/]node_modules[\\/]akanjs[\\/]/;
|
|
173
|
+
const defaultSkipPath = (absPath: string) => NODE_MODULES_RE.test(absPath) && !AKANJS_NODE_MODULE_RE.test(absPath);
|
|
174
|
+
|
|
165
175
|
type ExportValue = string | string[] | { [condition: string]: ExportValue | undefined };
|
|
166
176
|
|
|
167
177
|
const resolveNodePackageExport = async (workspaceRoot: string, specifier: string): Promise<PackageEntry | null> => {
|
|
@@ -178,13 +188,13 @@ const resolveNodePackageExport = async (workspaceRoot: string, specifier: string
|
|
|
178
188
|
main?: string;
|
|
179
189
|
};
|
|
180
190
|
const subpath = specifier === packageName ? "." : `.${specifier.slice(packageName.length)}`;
|
|
181
|
-
const exported =
|
|
191
|
+
const exported = resolvePackageExport(pkgJson.exports, subpath);
|
|
182
192
|
const rel = exported ?? (subpath === "." ? (pkgJson.module ?? pkgJson.main ?? "index.js") : null);
|
|
183
193
|
if (!rel || !rel.startsWith(".")) return null;
|
|
184
194
|
const entryFile = await resolveFileCandidate(path.resolve(pkgDir, rel));
|
|
185
195
|
if (!entryFile) return null;
|
|
186
196
|
const pkgEntryName = specifier;
|
|
187
|
-
return { pkgName: pkgEntryName, entryFile, pkgDir: path.dirname(entryFile) };
|
|
197
|
+
return { pkgName: pkgEntryName, entryFile, pkgDir: path.dirname(entryFile), preserveFilePath: true };
|
|
188
198
|
} catch {
|
|
189
199
|
return null;
|
|
190
200
|
}
|
|
@@ -207,6 +217,25 @@ const resolveExportValue = (value: ExportValue | undefined): string | null => {
|
|
|
207
217
|
return null;
|
|
208
218
|
};
|
|
209
219
|
|
|
220
|
+
const resolvePackageExport = (exportsMap: Record<string, ExportValue> | undefined, subpath: string): string | null => {
|
|
221
|
+
if (!exportsMap) return null;
|
|
222
|
+
const exact = resolveExportValue(exportsMap[subpath]);
|
|
223
|
+
if (exact) return exact;
|
|
224
|
+
|
|
225
|
+
for (const [key, value] of Object.entries(exportsMap)) {
|
|
226
|
+
const starIdx = key.indexOf("*");
|
|
227
|
+
if (starIdx === -1) continue;
|
|
228
|
+
const prefix = key.slice(0, starIdx);
|
|
229
|
+
const suffix = key.slice(starIdx + 1);
|
|
230
|
+
if (!subpath.startsWith(prefix) || !subpath.endsWith(suffix)) continue;
|
|
231
|
+
const wildcard = subpath.slice(prefix.length, subpath.length - suffix.length);
|
|
232
|
+
const resolved = resolveExportValue(value);
|
|
233
|
+
if (resolved) return resolved.replace("*", wildcard);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
return null;
|
|
237
|
+
};
|
|
238
|
+
|
|
210
239
|
const getPackageName = (specifier: string): string | null => {
|
|
211
240
|
const parts = specifier.split("/");
|
|
212
241
|
if (!parts[0]) return null;
|
package/package.json
CHANGED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
## Get Started
|
|
2
|
-
|
|
3
|
-
Run the code below.
|
|
4
|
-
|
|
5
|
-
```
|
|
6
|
-
bun run downloadEnv # Need to register your public key
|
|
7
|
-
|
|
8
|
-
bun i -g akanjs
|
|
9
|
-
|
|
10
|
-
bun i
|
|
11
|
-
|
|
12
|
-
cat <<EOF >> .env
|
|
13
|
-
# organization configuration, no need to change
|
|
14
|
-
AKAN_PUBLIC_REPO_NAME=<%= repoName %>
|
|
15
|
-
AKAN_PUBLIC_SERVE_DOMAIN="<%= serveDomain %>"
|
|
16
|
-
|
|
17
|
-
# development branch, debug, develop, main, etc. mainly it changes databases.
|
|
18
|
-
AKAN_PUBLIC_ENV=debug
|
|
19
|
-
|
|
20
|
-
# local, cloud, edge it changes the connection point of the clients.
|
|
21
|
-
AKAN_PUBLIC_OPERATION_MODE=local
|
|
22
|
-
# hybrid app specific config, will be depreciated in the future
|
|
23
|
-
APP_OPERATION_MODE=local
|
|
24
|
-
|
|
25
|
-
# backend service mode, federation, batch, all
|
|
26
|
-
SERVER_MODE=federation
|
|
27
|
-
|
|
28
|
-
# analyze the bundle size
|
|
29
|
-
ANALYZE=false
|
|
30
|
-
|
|
31
|
-
# log level, debug, info, warn, error
|
|
32
|
-
AKAN_PUBLIC_LOG_LEVEL=debug
|
|
33
|
-
EOF
|
|
34
|
-
|
|
35
|
-
akan serve-backend <%= appName %>
|
|
36
|
-
# or akan serve-frontend <%= appName %>, etc
|
|
37
|
-
```
|