stonyx 0.2.3-alpha.30 → 0.2.3-alpha.32
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/config/environment copy.ts +16 -0
- package/dist/cli/serve.js +6 -2
- package/dist/main.js +10 -6
- package/dist/util/resolve-entry-point.d.ts +1 -0
- package/dist/util/resolve-entry-point.js +14 -0
- package/dist/util/resolve-module-name.d.ts +14 -0
- package/dist/util/resolve-module-name.js +33 -0
- package/package.json +1 -1
- package/scripts/postinstall.js +22 -5
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { StoynxConfig } from 'stonyx';
|
|
2
|
+
|
|
3
|
+
// project configuration, override-able by listed environment variables
|
|
4
|
+
const {
|
|
5
|
+
DEBUG,
|
|
6
|
+
NODE_ENV,
|
|
7
|
+
} = process.env;
|
|
8
|
+
|
|
9
|
+
const environment = NODE_ENV ?? 'development';
|
|
10
|
+
|
|
11
|
+
const config: StoynxConfig = {
|
|
12
|
+
environment,
|
|
13
|
+
debug: DEBUG ?? environment === 'development',
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export default config;
|
package/dist/cli/serve.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
import { resolve } from 'path';
|
|
2
|
+
import { pathToFileURL } from 'url';
|
|
1
3
|
import { runStartupHooks, runShutdownHooks } from '../lifecycle.js';
|
|
2
4
|
import { importConfig } from '../util/import-config.js';
|
|
5
|
+
import { resolveEntryPoint } from '../util/resolve-entry-point.js';
|
|
3
6
|
export function createShutdownHandler(modules) {
|
|
4
7
|
let shuttingDown = false;
|
|
5
8
|
return async () => {
|
|
@@ -26,7 +29,8 @@ export function maybeRegisterAppShutdown(modules, appInstance, originalShutdown)
|
|
|
26
29
|
export default async function serve({ args }) {
|
|
27
30
|
const cwd = process.cwd();
|
|
28
31
|
const entryFlag = args.indexOf('--entry');
|
|
29
|
-
const
|
|
32
|
+
const entryArg = (entryFlag !== -1 && entryFlag + 1 < args.length) ? args[entryFlag + 1] : null;
|
|
33
|
+
const entryPoint = entryArg !== null ? resolve(cwd, entryArg) : resolveEntryPoint(`${cwd}/app`);
|
|
30
34
|
const config = await importConfig(`${cwd}/config/environment`);
|
|
31
35
|
const { default: Stonyx } = await import('../main.js');
|
|
32
36
|
new Stonyx(config, cwd);
|
|
@@ -36,7 +40,7 @@ export default async function serve({ args }) {
|
|
|
36
40
|
const shutdown = createShutdownHandler(modules);
|
|
37
41
|
process.on('SIGTERM', shutdown);
|
|
38
42
|
process.on('SIGINT', shutdown);
|
|
39
|
-
const entryModule = await import(
|
|
43
|
+
const entryModule = await import(pathToFileURL(entryPoint).href);
|
|
40
44
|
let appInstance;
|
|
41
45
|
if (entryModule.default) {
|
|
42
46
|
appInstance = new entryModule.default();
|
package/dist/main.js
CHANGED
|
@@ -15,9 +15,9 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import Chronicle from '@stonyx/logs';
|
|
17
17
|
import loadModules from './modules.js';
|
|
18
|
-
import { kebabCaseToCamelCase } from '@stonyx/utils/string';
|
|
19
18
|
import { mergeObject } from '@stonyx/utils/object';
|
|
20
19
|
import { importConfig } from './util/import-config.js';
|
|
20
|
+
import { resolveModuleName } from './util/resolve-module-name.js';
|
|
21
21
|
export default class Stonyx {
|
|
22
22
|
static initialized = false;
|
|
23
23
|
static modulePromises = {};
|
|
@@ -37,11 +37,15 @@ export default class Stonyx {
|
|
|
37
37
|
throw new Error('Stonyx requires full environment configuration on startup');
|
|
38
38
|
if (!rootPath)
|
|
39
39
|
throw new Error('Stonyx requires root project\'s path on startup');
|
|
40
|
-
// Transform config from stonyx-modules running as a standalone
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
40
|
+
// Transform config from stonyx-modules running as a standalone.
|
|
41
|
+
// Signal is the consumer's `package.json#name` (see resolveModuleName);
|
|
42
|
+
// this replaces the brittle `rootPath.includes('stonyx-')` heuristic so
|
|
43
|
+
// non-canonical rootPaths (worktrees, forks, renames) still work.
|
|
44
|
+
const moduleName = resolveModuleName(rootPath);
|
|
45
|
+
if (moduleName) {
|
|
46
|
+
const flatConfig = config;
|
|
47
|
+
const siblingModules = flatConfig.modules || {};
|
|
48
|
+
config = { [moduleName]: config, ...siblingModules };
|
|
45
49
|
delete config.modules;
|
|
46
50
|
}
|
|
47
51
|
this.config = config;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function resolveEntryPoint(basePath: string): string;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { existsSync } from 'fs';
|
|
2
|
+
import { resolve } from 'path';
|
|
3
|
+
const EXTENSIONS = ['ts', 'js'];
|
|
4
|
+
export function resolveEntryPoint(basePath) {
|
|
5
|
+
const matches = EXTENSIONS.filter(ext => existsSync(resolve(`${basePath}.${ext}`)));
|
|
6
|
+
if (matches.length === 0) {
|
|
7
|
+
throw new Error(`Entry point not found: ${basePath}.{ts,js}`);
|
|
8
|
+
}
|
|
9
|
+
if (matches.length > 1) {
|
|
10
|
+
console.warn(`Warning: both ${basePath}.ts and ${basePath}.js exist. Using .ts — delete the .js to silence this warning (it is likely a stale compiled artifact or postinstall stub).`);
|
|
11
|
+
}
|
|
12
|
+
const ext = matches[0];
|
|
13
|
+
return resolve(`${basePath}.${ext}`);
|
|
14
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve a stonyx standalone module's camelCase name from the consumer's
|
|
3
|
+
* `package.json#name`. Used by the standalone-config transform to wrap a flat
|
|
4
|
+
* config under the module's key when a stonyx module runs its own tests.
|
|
5
|
+
*
|
|
6
|
+
* Recognises:
|
|
7
|
+
* - `@stonyx/<kebab>` → `<camel>`
|
|
8
|
+
* - `stonyx-<kebab>` → `<camel>` (unscoped fallback)
|
|
9
|
+
* - Anything else → `null` (caller should skip the transform)
|
|
10
|
+
*
|
|
11
|
+
* Missing or malformed `package.json` returns `null` silently — matches the
|
|
12
|
+
* fail-safe semantics of the previous `rootPath.includes('stonyx-')` heuristic.
|
|
13
|
+
*/
|
|
14
|
+
export declare function resolveModuleName(rootPath: string): string | null;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { readFileSync } from 'fs';
|
|
2
|
+
import { kebabCaseToCamelCase } from '@stonyx/utils/string';
|
|
3
|
+
/**
|
|
4
|
+
* Resolve a stonyx standalone module's camelCase name from the consumer's
|
|
5
|
+
* `package.json#name`. Used by the standalone-config transform to wrap a flat
|
|
6
|
+
* config under the module's key when a stonyx module runs its own tests.
|
|
7
|
+
*
|
|
8
|
+
* Recognises:
|
|
9
|
+
* - `@stonyx/<kebab>` → `<camel>`
|
|
10
|
+
* - `stonyx-<kebab>` → `<camel>` (unscoped fallback)
|
|
11
|
+
* - Anything else → `null` (caller should skip the transform)
|
|
12
|
+
*
|
|
13
|
+
* Missing or malformed `package.json` returns `null` silently — matches the
|
|
14
|
+
* fail-safe semantics of the previous `rootPath.includes('stonyx-')` heuristic.
|
|
15
|
+
*/
|
|
16
|
+
export function resolveModuleName(rootPath) {
|
|
17
|
+
let pkg;
|
|
18
|
+
try {
|
|
19
|
+
const raw = readFileSync(`${rootPath}/package.json`, 'utf8');
|
|
20
|
+
pkg = JSON.parse(raw);
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
const name = typeof pkg.name === 'string' ? pkg.name : '';
|
|
26
|
+
if (name.startsWith('@stonyx/')) {
|
|
27
|
+
return kebabCaseToCamelCase(name.slice('@stonyx/'.length));
|
|
28
|
+
}
|
|
29
|
+
if (name.startsWith('stonyx-')) {
|
|
30
|
+
return kebabCaseToCamelCase(name.slice('stonyx-'.length));
|
|
31
|
+
}
|
|
32
|
+
return null;
|
|
33
|
+
}
|
package/package.json
CHANGED
package/scripts/postinstall.js
CHANGED
|
@@ -7,14 +7,31 @@ const { copyFile, createDirectory } = await import('@stonyx/utils/file');
|
|
|
7
7
|
|
|
8
8
|
const projectDir = process.env.INIT_CWD;
|
|
9
9
|
const configDir = `${projectDir}/config`;
|
|
10
|
-
const envFile = 'environment.js';
|
|
11
10
|
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
|
|
11
|
+
// Detect consumer project type: presence of `tsconfig.json` in the consumer
|
|
12
|
+
// root signals a TypeScript project (see abofs/stonyx#62). TS consumers can't
|
|
13
|
+
// use the `.js` stub, so we ship both templates and copy the matching one.
|
|
14
|
+
const isTypeScriptConsumer = existsSync(`${projectDir}/tsconfig.json`);
|
|
15
|
+
const extension = isTypeScriptConsumer ? 'ts' : 'js';
|
|
16
|
+
const envFile = `environment.${extension}`;
|
|
17
|
+
const templateFile = `environment copy.${extension}`;
|
|
18
|
+
|
|
19
|
+
// Skip if the consumer ships its own `config/environment copy.{ts,js}` template —
|
|
20
|
+
// they manage their own bootstrap (see abofs/stonyx#54, extended in abofs/stonyx#62
|
|
21
|
+
// to honor either extension).
|
|
22
|
+
if (
|
|
23
|
+
existsSync(`${configDir}/environment copy.ts`) ||
|
|
24
|
+
existsSync(`${configDir}/environment copy.js`)
|
|
25
|
+
) process.exit(0);
|
|
26
|
+
|
|
27
|
+
// Don't overwrite an existing consumer config (either extension).
|
|
28
|
+
if (
|
|
29
|
+
existsSync(`${configDir}/environment.ts`) ||
|
|
30
|
+
existsSync(`${configDir}/environment.js`)
|
|
31
|
+
) process.exit(0);
|
|
15
32
|
|
|
16
33
|
createDirectory(configDir);
|
|
17
34
|
|
|
18
|
-
copyFile(`./config
|
|
35
|
+
copyFile(`./config/${templateFile}`, `${configDir}/${envFile}`).then(result => {
|
|
19
36
|
if (result) console.log(`Stonyx: ${envFile} has been successfully created. Please see README.md for more information.`);
|
|
20
37
|
});
|