Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@node-in-layers/core",
"type": "module",
"version": "1.1.0",
"version": "1.1.2",
"description": "The core library for the Node In Layers rapid web development framework.",
"main": "index.js",
"scripts": {
Expand Down Expand Up @@ -84,7 +84,7 @@
},
"dependencies": {
"async-lock": "^1.4.1",
"axios": "^1.7.7",
"axios": "^1.7.9",
"import-meta-resolve": "^4.1.0",
"lodash": "^4.17.21",
"loglevel": "^1.9.2",
Expand Down
45 changes: 37 additions & 8 deletions src/dependencies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,48 @@ import log from 'loglevel'
import { getLogLevelName, isConfig, validateConfig } from './libs.js'
import {
Config,
RootLogger,
LogFormat,
DependenciesServices,
DependenciesServicesProps,
DependenciesFeatures,
App,
CommonDependencies,
CommonContext,
CoreNamespace,
NodeDependencies,
} from './types.js'
import { memoizeValue } from './utils.js'

const name = CoreNamespace.dependencies

type DependenciesServicesProps = Readonly<{
environment: string
workingDirectory: string
nodeOverrides?: Partial<NodeDependencies>
}>

type DependenciesServices<TConfig extends Config> = Readonly<{
loadConfig: () => Promise<TConfig>
configureLogging: (config: TConfig) => RootLogger
getConstants: () => {
workingDirectory: string
environment: string
}
getNodeServices: () => NodeDependencies
getDependencies: (
commonDependencies: CommonContext<TConfig>,
app: App
) => Promise<Record<string, any>>
}>

type DependenciesFeatures<TConfig extends Config> = Readonly<{
loadDependencies: <TDependencies extends Record<string, any> = object>(
environmentOrConfig: string | TConfig
) => Promise<CommonContext<TConfig> & TDependencies>
}>

const services = {
create: <TConfig extends Config>({
environment,
workingDirectory,
nodeOverrides,
}: DependenciesServicesProps): DependenciesServices<TConfig> => {
const useFullLogFormat = () => {
const originalFactory = log.methodFactory
Expand Down Expand Up @@ -136,13 +162,16 @@ const services = {
}

const getNodeServices = () => {
return {
fs: nodeFS,
}
return merge(
{
fs: nodeFS,
},
nodeOverrides || {}
)
}

const getDependencies = (
commonDependencies: CommonDependencies<TConfig>,
commonDependencies: CommonContext<TConfig>,
app: App
) => {
if (app.dependencies) {
Expand Down
4 changes: 3 additions & 1 deletion src/entries.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import omit from 'lodash/omit.js'
import * as dependenciesApp from './dependencies.js'
import * as layersApp from './layers.js'
import { Config, CoreNamespace } from './types.js'
import { Config, CoreNamespace, NodeDependencies } from './types.js'

const loadSystem = async <TConfig extends Config = Config>(args: {
environment: string
config?: TConfig
nodeOverrides?: NodeDependencies
}) => {
const depServices = dependenciesApp.services.create({
environment: args.environment,
workingDirectory: process.cwd(),
nodeOverrides: args.nodeOverrides,
})
const depFeatures = dependenciesApp.features.create({
services: {
Expand Down
40 changes: 25 additions & 15 deletions src/layers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,28 @@ import merge from 'lodash/merge.js'
import {
App,
AppLayer,
LayerDependencies,
CommonDependencies,
LayerServices,
LayerServicesLayer,
LayerContext,
CommonContext,
CoreNamespace,
} from './types.js'
import { getLayersUnavailable } from './libs.js'

const name = CoreNamespace.layers

type LayerServices = Readonly<{
loadLayer: (
app: App,
layer: string,
existingLayers: object
) => undefined | Record<string, any>
}>

type LayerServicesLayer = {
services: {
[CoreNamespace.layers]: LayerServices
}
}

const services = {
create: (): LayerServices => {
const loadLayer = (app: App, layer: string, existingLayers: object) => {
Expand All @@ -37,9 +49,9 @@ const services = {
}

const features = {
create: (props: CommonDependencies & LayerServicesLayer) => {
create: (context: CommonContext & LayerServicesLayer) => {
const loadLayers = () => {
const layersInOrder = props.config[CoreNamespace.root].layerOrder
const layersInOrder = context.config[CoreNamespace.root].layerOrder
const antiLayers = getLayersUnavailable(layersInOrder)
const ignoreLayers = [CoreNamespace.layers, CoreNamespace.dependencies]
.map(l => `services.${l}`)
Expand All @@ -49,20 +61,18 @@ const features = {
)
)
return omit(
props.config[CoreNamespace.root].apps.reduce(
(existingLayers: LayerDependencies, app) => {
context.config[CoreNamespace.root].apps.reduce(
(existingLayers: LayerContext, app) => {
return layersInOrder.reduce(
(existingLayers2: LayerDependencies, layer) => {
(existingLayers2: LayerContext, layer) => {
// We have to remove existing layers that we don't want to be exposed.
const correctContext = omit(existingLayers, [
...antiLayers(layer),
...ignoreLayers,
])
const instance = props.services[CoreNamespace.layers].loadLayer(
app,
layer,
correctContext
)
const instance = context.services[
CoreNamespace.layers
].loadLayer(app, layer, correctContext)
if (!instance) {
return existingLayers2
}
Expand All @@ -76,7 +86,7 @@ const features = {
existingLayers
)
},
props
context
),
ignoreLayers
)
Expand Down
101 changes: 27 additions & 74 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,15 @@ type AppLayer<
TDependencies extends object = object,
TLayer extends object = object,
> = Readonly<{
create: (dependencies: LayerDependencies<TConfig, TDependencies>) => TLayer
create: (dependencies: LayerContext<TConfig, TDependencies>) => TLayer
}>

type CommonDependencies<TConfig extends Config = Config> = Readonly<{
node: {
fs: FSLike
}
type NodeDependencies = Readonly<{
fs: FSLike
}>

type CommonContext<TConfig extends Config = Config> = Readonly<{
node: NodeDependencies
config: TConfig
log: RootLogger
constants: {
Expand All @@ -89,127 +91,81 @@ type CommonDependencies<TConfig extends Config = Config> = Readonly<{
}
}>

type LayerDependencies<
type LayerContext<
TConfig extends Config = Config,
TDependencies extends object = object,
> = CommonDependencies<TConfig> & TDependencies
> = CommonContext<TConfig> & TDependencies

type ServicesDependencies<
type ServicesContext<
TConfig extends Config = Config,
TServices extends object = object,
TDependencies extends object = object,
> = LayerDependencies<
> = LayerContext<
TConfig,
{
services: TServices
} & TDependencies
>

type ServicesLayer<
type ServicesLayerFactory<
TConfig extends Config = Config,
TServices extends object = object,
TDependencies extends object = object,
TLayer extends object = object,
> = Readonly<{
create: (
dependencies: ServicesDependencies<TConfig, TServices, TDependencies>
context: ServicesContext<TConfig, TServices, TDependencies>
) => TLayer
}>

type DependenciesLayer<
TConfig extends Config = Config,
TDependencies extends object = object,
> = Readonly<{
create: (deps: CommonDependencies<TConfig>) => Promise<TDependencies>
create: (context: CommonContext<TConfig>) => Promise<TDependencies>
}>

type FeaturesDependencies<
type FeaturesContext<
TConfig extends Config = Config,
TServices extends object = object,
TFeatures extends object = object,
TDependencies extends object = object,
> = LayerDependencies<
> = LayerContext<
TConfig,
{
services: TServices
features: TFeatures
} & TDependencies
>

type FeaturesLayer<
type FeaturesLayerFactory<
TConfig extends Config = Config,
TDependencies extends object = object,
TServices extends object = object,
TFeatures extends object = object,
TLayer extends object = object,
> = Readonly<{
create: (
dependencies: FeaturesDependencies<
TConfig,
TServices,
TFeatures,
TDependencies
>
context: FeaturesContext<TConfig, TServices, TFeatures, TDependencies>
) => TLayer
}>

type System<
TConfig extends Config = Config,
TFeatures extends object = object,
TServices extends object = object,
> = CommonDependencies<TConfig> & {
> = CommonContext<TConfig> & {
services: TServices
features: TFeatures
}

type DependenciesServicesProps = Readonly<{
environment: string
workingDirectory: string
}>

type DependenciesServices<TConfig extends Config> = Readonly<{
loadConfig: () => Promise<TConfig>
configureLogging: (config: TConfig) => RootLogger
getConstants: () => {
workingDirectory: string
environment: string
}
getNodeServices: () => {
fs: FSLike
}
getDependencies: (
commonDependencies: CommonDependencies<TConfig>,
app: App
) => Promise<Record<string, any>>
}>

type DependenciesFeatures<TConfig extends Config> = Readonly<{
loadDependencies: <TDependencies extends Record<string, any> = object>(
environmentOrConfig: string | TConfig
) => Promise<CommonDependencies<TConfig> & TDependencies>
}>

type App = Readonly<{
name: string
services?: AppLayer<Config, any>
features?: AppLayer<Config, any>
dependencies?: DependenciesLayer<Config, any>
}>

type LayerServices = Readonly<{
loadLayer: (
app: App,
layer: string,
existingLayers: object
) => undefined | Record<string, any>
}>

type LayerServicesLayer = {
services: {
[CoreNamespace.layers]: LayerServices
}
}

export {
Config,
App,
Expand All @@ -218,18 +174,15 @@ export {
LogLevel,
LogLevelNames,
AppLayer,
LayerDependencies,
ServicesDependencies,
ServicesLayer,
FeaturesDependencies,
LayerContext,
ServicesContext,
ServicesLayerFactory,
FeaturesContext,
System,
DependenciesServices,
DependenciesServicesProps,
DependenciesFeatures,
CommonDependencies,
LayerServices,
LayerServicesLayer,
RootLogger,
CommonContext,
CoreNamespace,
FeaturesLayer,
FeaturesLayerFactory,
Logger,
NodeDependencies,
}
Loading