@jk2908/solas 0.3.0 → 0.3.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/CHANGELOG.md +7 -0
- package/dist/internal/codegen/config.js +17 -8
- package/dist/internal/codegen/environments.js +7 -7
- package/dist/internal/codegen/manifest.js +3 -3
- package/dist/internal/codegen/maps.js +11 -15
- package/dist/internal/codegen/utils.d.ts +10 -0
- package/dist/internal/codegen/utils.js +27 -2
- package/dist/internal/navigation/use-search-params.d.ts +11 -1
- package/dist/internal/navigation/use-search-params.js +21 -2
- package/dist/navigation.d.ts +2 -2
- package/dist/navigation.js +2 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.3.1 - 2026-04-07
|
|
4
|
+
|
|
5
|
+
- Fixed `useSearchParams()` client builds.
|
|
6
|
+
- Reworked the code generators to keep the source templates readable while still emitting tidy generated files.
|
|
7
|
+
- Added a shared template dedent helper for generated source and tightened nested object and route map indentation.
|
|
8
|
+
- Made generated config output emit logger code only when a logger level is configured.
|
|
9
|
+
|
|
3
10
|
## 0.3.0 - 2026-04-07
|
|
4
11
|
|
|
5
12
|
- Fixed `useSearchParams()` hydration so query-driven ui uses the initial request url on first render.
|
|
@@ -1,19 +1,28 @@
|
|
|
1
1
|
import { Solas } from '../../solas.js';
|
|
2
|
-
import { AUTOGEN_MSG, toSourceLiteral } from './utils.js';
|
|
2
|
+
import { AUTOGEN_MSG, source, toSourceLiteral } from './utils.js';
|
|
3
3
|
/**
|
|
4
4
|
* Generates the code to create an exported config object
|
|
5
5
|
*/
|
|
6
6
|
export function writeConfig(config) {
|
|
7
|
-
|
|
7
|
+
const loggerLevel = config.logger?.level;
|
|
8
|
+
const importLines = [
|
|
9
|
+
`import type { PluginConfig } from '${Solas.Config.PKG_NAME}'`,
|
|
10
|
+
loggerLevel ? `import { Logger } from '${Solas.Config.PKG_NAME}/utils/logger'` : '',
|
|
11
|
+
]
|
|
12
|
+
.filter(Boolean)
|
|
13
|
+
.join('\n');
|
|
14
|
+
const configStatement = `const config = ${toSourceLiteral(config)} as const satisfies PluginConfig`;
|
|
15
|
+
const loggerStatement = loggerLevel
|
|
16
|
+
? `Logger.defaultLevel = ${toSourceLiteral(loggerLevel)}`
|
|
17
|
+
: '';
|
|
18
|
+
return source `
|
|
8
19
|
${AUTOGEN_MSG}
|
|
9
20
|
|
|
10
|
-
|
|
11
|
-
import { Logger } from '${Solas.Config.PKG_NAME}/utils/logger'
|
|
21
|
+
${importLines}
|
|
12
22
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
if (config.logger?.level) Logger.defaultLevel = config.logger.level
|
|
23
|
+
${configStatement}
|
|
24
|
+
${loggerStatement}
|
|
16
25
|
|
|
17
26
|
export { config }
|
|
18
|
-
|
|
27
|
+
`;
|
|
19
28
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { Solas } from '../../solas.js';
|
|
2
|
-
import { AUTOGEN_MSG } from './utils.js';
|
|
2
|
+
import { AUTOGEN_MSG, source } from './utils.js';
|
|
3
3
|
/**
|
|
4
4
|
* Generates the RSC entry code
|
|
5
5
|
*/
|
|
6
6
|
export function writeRSCEntry() {
|
|
7
|
-
return `
|
|
7
|
+
return source `
|
|
8
8
|
${AUTOGEN_MSG}
|
|
9
9
|
|
|
10
10
|
import { createHandler } from '${Solas.Config.PKG_NAME}/env/rsc'
|
|
@@ -20,27 +20,27 @@ export function writeRSCEntry() {
|
|
|
20
20
|
export default createHandler(config, manifest, importMap, artifactManifest)
|
|
21
21
|
|
|
22
22
|
import.meta.hot?.accept()
|
|
23
|
-
|
|
23
|
+
`;
|
|
24
24
|
}
|
|
25
25
|
/**
|
|
26
26
|
* Generates the SSR entry code
|
|
27
27
|
*/
|
|
28
28
|
export function writeSSREntry() {
|
|
29
|
-
return `
|
|
29
|
+
return source `
|
|
30
30
|
${AUTOGEN_MSG}
|
|
31
31
|
|
|
32
32
|
export { prerender, resume, ssr } from '${Solas.Config.PKG_NAME}/env/ssr'
|
|
33
|
-
|
|
33
|
+
`;
|
|
34
34
|
}
|
|
35
35
|
/**
|
|
36
36
|
* Generates the browser entry code
|
|
37
37
|
*/
|
|
38
38
|
export function writeBrowserEntry() {
|
|
39
|
-
return `
|
|
39
|
+
return source `
|
|
40
40
|
${AUTOGEN_MSG}
|
|
41
41
|
|
|
42
42
|
import { browser } from '${Solas.Config.PKG_NAME}/env/browser'
|
|
43
43
|
|
|
44
44
|
browser()
|
|
45
|
-
|
|
45
|
+
`;
|
|
46
46
|
}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { Solas } from '../../solas.js';
|
|
2
|
-
import { AUTOGEN_MSG, toSourceLiteral } from './utils.js';
|
|
2
|
+
import { AUTOGEN_MSG, source, toSourceLiteral } from './utils.js';
|
|
3
3
|
/**
|
|
4
4
|
* Generates the code to create an exported manifest object
|
|
5
5
|
*/
|
|
6
6
|
export function writeManifest(manifest) {
|
|
7
|
-
return `
|
|
7
|
+
return source `
|
|
8
8
|
${AUTOGEN_MSG}
|
|
9
9
|
|
|
10
10
|
import type { Manifest } from '${Solas.Config.PKG_NAME}'
|
|
11
11
|
|
|
12
12
|
export const manifest = ${toSourceLiteral(manifest)} as const satisfies Manifest
|
|
13
|
-
|
|
13
|
+
`;
|
|
14
14
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Solas } from '../../solas.js';
|
|
2
|
-
import { AUTOGEN_MSG, toIdentifier, toIdentifierList, toRelativeModuleSpecifier, toStringLiteral, } from './utils.js';
|
|
2
|
+
import { AUTOGEN_MSG, indent, source, toIdentifier, toIdentifierList, toRelativeModuleSpecifier, toStringLiteral, } from './utils.js';
|
|
3
3
|
/**
|
|
4
4
|
* Generates the import map for all route components, endpoints, layouts, shells, and middlewares
|
|
5
5
|
*/
|
|
@@ -61,26 +61,22 @@ export function writeMaps(imports, modules) {
|
|
|
61
61
|
parts.push(`middlewares: [${middleware}]`);
|
|
62
62
|
}
|
|
63
63
|
if (parts.length === 0)
|
|
64
|
-
return
|
|
65
|
-
return
|
|
64
|
+
return `${toStringLiteral(moduleId)}: {}`;
|
|
65
|
+
return `${toStringLiteral(moduleId)}: {\n${parts.map(part => indent(part, 1)).join(',\n')}\n}`;
|
|
66
66
|
});
|
|
67
|
-
|
|
67
|
+
const importLines = [...statics, ...dynamics].join('\n');
|
|
68
|
+
const entries = map.map(entry => indent(entry, 1)).join(',\n');
|
|
69
|
+
return source `
|
|
68
70
|
${AUTOGEN_MSG}
|
|
69
71
|
|
|
70
72
|
import type { ImportMap } from '${Solas.Config.PKG_NAME}'
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
`
|
|
76
|
-
: ''}${dynamics.length
|
|
77
|
-
? `${dynamics.join('\n')}
|
|
78
|
-
|
|
79
|
-
`
|
|
73
|
+
${importLines
|
|
74
|
+
? `
|
|
75
|
+
${importLines}`
|
|
80
76
|
: ''}
|
|
81
77
|
|
|
82
78
|
export const importMap = {
|
|
83
|
-
|
|
79
|
+
${entries}
|
|
84
80
|
} as const satisfies ImportMap
|
|
85
|
-
|
|
81
|
+
`;
|
|
86
82
|
}
|
|
@@ -15,7 +15,17 @@ export declare function toIdentifierList(values: readonly (string | null)[], lab
|
|
|
15
15
|
* Escape text into a safe string literal for generated source
|
|
16
16
|
*/
|
|
17
17
|
export declare function toStringLiteral(value: string, quoteStyle?: "'" | '"'): string;
|
|
18
|
+
/**
|
|
19
|
+
* Dedent an interpolated template literal while preserving indentation for
|
|
20
|
+
* multiline substitutions
|
|
21
|
+
*/
|
|
22
|
+
export declare function source(strings: TemplateStringsArray, ...values: Array<string | number | boolean | false | null | undefined>): string;
|
|
18
23
|
/**
|
|
19
24
|
* Emit readable ts source for generated config and manifest data
|
|
20
25
|
*/
|
|
21
26
|
export declare function toSourceLiteral(value: unknown, level?: number): string;
|
|
27
|
+
/**
|
|
28
|
+
* Indent each line of a block of source code by the specified level for embedding in
|
|
29
|
+
* generated output
|
|
30
|
+
*/
|
|
31
|
+
export declare function indent(value: string, level?: number): string;
|
|
@@ -60,6 +60,31 @@ export function toStringLiteral(value, quoteStyle = "'") {
|
|
|
60
60
|
.replace(/\r/g, '\\r')
|
|
61
61
|
.replace(/\t/g, '\\t')}${quoteStyle}`;
|
|
62
62
|
}
|
|
63
|
+
/**
|
|
64
|
+
* Dedent an interpolated template literal while preserving indentation for
|
|
65
|
+
* multiline substitutions
|
|
66
|
+
*/
|
|
67
|
+
export function source(strings, ...values) {
|
|
68
|
+
let text = strings[0] ?? '';
|
|
69
|
+
for (let index = 0; index < values.length; index += 1) {
|
|
70
|
+
const value = values[index];
|
|
71
|
+
const indentation = text.match(/(?:^|\n)([ \t]*)$/)?.[1] ?? '';
|
|
72
|
+
const chunk = value === false || value == null ? '' : String(value);
|
|
73
|
+
text += chunk.replace(/\n/g, `\n${indentation}`);
|
|
74
|
+
text += strings[index + 1] ?? '';
|
|
75
|
+
}
|
|
76
|
+
const lines = text.replace(/^\n+|\n+$/g, '').split('\n');
|
|
77
|
+
const margin = lines
|
|
78
|
+
.filter(line => line.trim().length > 0)
|
|
79
|
+
.reduce((smallest, line) => {
|
|
80
|
+
const indentation = line.match(/^[ \t]*/)?.[0].length ?? 0;
|
|
81
|
+
return Math.min(smallest, indentation);
|
|
82
|
+
}, Number.POSITIVE_INFINITY);
|
|
83
|
+
if (!Number.isFinite(margin) || margin === 0) {
|
|
84
|
+
return lines.join('\n');
|
|
85
|
+
}
|
|
86
|
+
return lines.map(line => line.slice(margin)).join('\n');
|
|
87
|
+
}
|
|
63
88
|
/**
|
|
64
89
|
* Convert a string into a valid unquoted property key if possible, otherwise quote it
|
|
65
90
|
* as a string literal for generated source
|
|
@@ -120,7 +145,7 @@ export function toSourceLiteral(value, level = 0) {
|
|
|
120
145
|
}
|
|
121
146
|
return `${prefix}${source.replace(/\n/g, `\n${INDENT.repeat(level + 1)}`)}`;
|
|
122
147
|
}
|
|
123
|
-
return `${prefix}${toSourceLiteral(entryValue, level + 1)
|
|
148
|
+
return `${prefix}${toSourceLiteral(entryValue, level + 1)}`;
|
|
124
149
|
})
|
|
125
150
|
.join(',\n'),
|
|
126
151
|
`${INDENT.repeat(level)}}`,
|
|
@@ -132,7 +157,7 @@ export function toSourceLiteral(value, level = 0) {
|
|
|
132
157
|
* Indent each line of a block of source code by the specified level for embedding in
|
|
133
158
|
* generated output
|
|
134
159
|
*/
|
|
135
|
-
function indent(value, level = 1) {
|
|
160
|
+
export function indent(value, level = 1) {
|
|
136
161
|
const prefix = INDENT.repeat(level);
|
|
137
162
|
return value
|
|
138
163
|
.split('\n')
|
|
@@ -1 +1,11 @@
|
|
|
1
|
-
export
|
|
1
|
+
export type ReadonlySearchParams = Iterable<[string, string]> & {
|
|
2
|
+
entries(): IterableIterator<[string, string]>;
|
|
3
|
+
forEach(callbackfn: (value: string, key: string, parent: ReadonlySearchParams) => void, thisArg?: unknown): void;
|
|
4
|
+
get(name: string): string | null;
|
|
5
|
+
getAll(name: string): string[];
|
|
6
|
+
has(name: string, value?: string): boolean;
|
|
7
|
+
keys(): IterableIterator<string>;
|
|
8
|
+
toString(): string;
|
|
9
|
+
values(): IterableIterator<string>;
|
|
10
|
+
};
|
|
11
|
+
export declare function useSearchParams(): ReadonlySearchParams;
|
|
@@ -1,6 +1,25 @@
|
|
|
1
1
|
import { useMemo, useSyncExternalStore } from 'react';
|
|
2
|
-
import { useRouter } from '../../router.js';
|
|
3
2
|
import { Solas } from '../../solas.js';
|
|
3
|
+
import { useRouter } from '../router/use-router.js';
|
|
4
|
+
function createReadonlySearchParams(search) {
|
|
5
|
+
const params = new URLSearchParams(search);
|
|
6
|
+
const readonlyParams = {
|
|
7
|
+
[Symbol.iterator]: () => params[Symbol.iterator](),
|
|
8
|
+
entries: () => params.entries(),
|
|
9
|
+
forEach: (callbackfn, thisArg) => {
|
|
10
|
+
params.forEach((value, key) => {
|
|
11
|
+
callbackfn.call(thisArg, value, key, readonlyParams);
|
|
12
|
+
});
|
|
13
|
+
},
|
|
14
|
+
get: name => params.get(name),
|
|
15
|
+
getAll: name => params.getAll(name),
|
|
16
|
+
has: (name, value) => params.has(name, value),
|
|
17
|
+
keys: () => params.keys(),
|
|
18
|
+
toString: () => params.toString(),
|
|
19
|
+
values: () => params.values(),
|
|
20
|
+
};
|
|
21
|
+
return readonlyParams;
|
|
22
|
+
}
|
|
4
23
|
export function useSearchParams() {
|
|
5
24
|
const { url } = useRouter();
|
|
6
25
|
const search = useSyncExternalStore(fn => {
|
|
@@ -11,5 +30,5 @@ export function useSearchParams() {
|
|
|
11
30
|
window.removeEventListener(Solas.Events.names.NAVIGATION, fn);
|
|
12
31
|
};
|
|
13
32
|
}, () => window.location.search, () => url?.search);
|
|
14
|
-
return useMemo(() =>
|
|
33
|
+
return useMemo(() => createReadonlySearchParams(search), [search]);
|
|
15
34
|
}
|
package/dist/navigation.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { HttpException, abort, isHttpException, } from './internal/navigation/http-exception.js';
|
|
2
1
|
export { HttpExceptionBoundary } from './internal/navigation/http-exception-boundary.js';
|
|
2
|
+
export { HttpException, abort, isHttpException, } from './internal/navigation/http-exception.js';
|
|
3
3
|
export { Link } from './internal/navigation/link.js';
|
|
4
|
-
export { Redirect, isRedirect, redirect } from './internal/navigation/redirect.js';
|
|
5
4
|
export { RedirectBoundary } from './internal/navigation/redirect-boundary.js';
|
|
5
|
+
export { Redirect, isRedirect, redirect } from './internal/navigation/redirect.js';
|
|
6
6
|
export { useSearchParams } from './internal/navigation/use-search-params.js';
|
package/dist/navigation.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { HttpException, abort, isHttpException, } from './internal/navigation/http-exception.js';
|
|
2
1
|
export { HttpExceptionBoundary } from './internal/navigation/http-exception-boundary.js';
|
|
2
|
+
export { HttpException, abort, isHttpException, } from './internal/navigation/http-exception.js';
|
|
3
3
|
export { Link } from './internal/navigation/link.js';
|
|
4
|
-
export { Redirect, isRedirect, redirect } from './internal/navigation/redirect.js';
|
|
5
4
|
export { RedirectBoundary } from './internal/navigation/redirect-boundary.js';
|
|
5
|
+
export { Redirect, isRedirect, redirect } from './internal/navigation/redirect.js';
|
|
6
6
|
export { useSearchParams } from './internal/navigation/use-search-params.js';
|