@obsidiane/meridiane 0.0.6 → 0.0.10
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/README.md +19 -31
- package/cli.js +64 -44
- package/package.json +3 -7
- package/templates/_lib_template/package.json +2 -1
- package/templates/_lib_template/src/lib/bridge/rest/api-platform.adapter.ts +48 -47
- package/templates/_lib_template/src/lib/bridge/rest/query-builder.ts +29 -29
- package/templates/_lib_template/src/lib/bridge/sse/eventsource-wrapper.ts +50 -54
- package/templates/_lib_template/src/lib/bridge/sse/mercure-topic.mapper.ts +48 -0
- package/templates/_lib_template/src/lib/bridge/sse/mercure-url.builder.ts +7 -7
- package/templates/_lib_template/src/lib/bridge/sse/mercure.adapter.ts +104 -49
- package/templates/_lib_template/src/lib/bridge/sse/ref-count-topic.registry.ts +23 -21
- package/templates/_lib_template/src/lib/bridge.types.ts +33 -0
- package/templates/_lib_template/src/lib/facades/bridge.facade.ts +116 -0
- package/templates/_lib_template/src/lib/facades/facade.factory.ts +21 -19
- package/templates/_lib_template/src/lib/facades/facade.interface.ts +13 -18
- package/templates/_lib_template/src/lib/facades/resource.facade.ts +42 -56
- package/templates/_lib_template/src/lib/interceptors/bridge-debug.interceptor.ts +32 -0
- package/templates/_lib_template/src/lib/interceptors/bridge-defaults.interceptor.ts +53 -0
- package/templates/_lib_template/src/lib/interceptors/content-type.interceptor.ts +36 -37
- package/templates/_lib_template/src/lib/ports/realtime.port.ts +5 -3
- package/templates/_lib_template/src/lib/ports/resource-repository.port.ts +14 -15
- package/templates/_lib_template/src/lib/provide-bridge.ts +122 -19
- package/templates/_lib_template/src/lib/tokens.ts +14 -1
- package/templates/_lib_template/src/lib/utils/url.ts +15 -0
- package/templates/_lib_template/src/models/index.ts +0 -1
- package/templates/_lib_template/src/public-api.ts +3 -2
- package/tools/build.js +104 -0
- package/tools/core/generate.js +152 -0
- package/tools/core/json.js +71 -0
- package/tools/core/lib-name.js +15 -0
- package/tools/core/logger.js +51 -0
- package/tools/core/paths.js +17 -0
- package/tools/core/spec.js +59 -0
- package/tools/core/standalone.js +117 -0
- package/tools/dev.js +218 -0
- package/tools/generator/models/handlebars.js +8 -2
- package/tools/generator/models/naming.js +21 -15
- package/tools/generator/models/openapi-to-models.js +75 -38
- package/tools/generator/models/schema-utils.js +84 -66
- package/tools/generator/models/templates/model.hbs +3 -3
- package/tools/generator/models/utils.js +1 -2
- package/models.config.example.js +0 -24
- package/templates/_lib_template/src/lib/bridge/credentials.policy.ts +0 -9
- package/templates/_lib_template/src/lib/utils/utils.ts +0 -21
- package/templates/_lib_template/tsconfig.spec.json +0 -14
- package/tools/generate-lib.js +0 -136
- package/tools/generate-models.js +0 -121
package/models.config.example.js
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
// Exemple de configuration pour la génération des modèles.
|
|
2
|
-
// Copiez ce fichier en `models.config.js` dans le dossier où vous lancez la commande (`meridiane models`).
|
|
3
|
-
// Format CommonJS pour éviter les warnings Node dans la plupart des workspaces Angular.
|
|
4
|
-
|
|
5
|
-
module.exports = {
|
|
6
|
-
// Dossier de sortie (relatif au CWD)
|
|
7
|
-
outDir: 'projects/backend-bridge/src/models',
|
|
8
|
-
|
|
9
|
-
// Chemin d'import de `Item` dans les templates (relatif au fichier généré)
|
|
10
|
-
itemImportPath: '../lib/ports/resource-repository.port',
|
|
11
|
-
|
|
12
|
-
// Contrôle des propriétés optionnelles
|
|
13
|
-
// - 'all-optional': toutes les props sont optionnelles
|
|
14
|
-
// - 'spec': respecte le tableau `required` de la spec
|
|
15
|
-
requiredMode: 'all-optional',
|
|
16
|
-
|
|
17
|
-
// Préférence entre variantes de schémas (.jsonld, .jsonapi ou aucune)
|
|
18
|
-
// Valeurs possibles: 'jsonld' | 'jsonapi' | 'none'
|
|
19
|
-
preferFlavor: 'jsonld',
|
|
20
|
-
|
|
21
|
-
// Hydra: regex pour les schémas de base à ignorer (merge allOf / filtrage)
|
|
22
|
-
// Peut être une RegExp ou une string passée à `new RegExp(...)`
|
|
23
|
-
hydraBaseRegex: /^Hydra(?:Item|Collection)BaseSchema$/,
|
|
24
|
-
};
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import {WritableSignal} from '@angular/core';
|
|
2
|
-
import {Item} from '../ports/resource-repository.port';
|
|
3
|
-
|
|
4
|
-
export function upsertInSignal(
|
|
5
|
-
signal: WritableSignal<readonly Item[]>,
|
|
6
|
-
item: Item,
|
|
7
|
-
): void {
|
|
8
|
-
signal.update(items => {
|
|
9
|
-
|
|
10
|
-
const id = item['@id'];
|
|
11
|
-
const existingIndex = items.findIndex(it => it['@id'] === id);
|
|
12
|
-
|
|
13
|
-
if (existingIndex === -1) {
|
|
14
|
-
return [item, ...items];
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const next = items.slice() as Item[];
|
|
18
|
-
next[existingIndex] = item;
|
|
19
|
-
return next;
|
|
20
|
-
});
|
|
21
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */
|
|
2
|
-
/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */
|
|
3
|
-
{
|
|
4
|
-
"extends": "../../tsconfig.json",
|
|
5
|
-
"compilerOptions": {
|
|
6
|
-
"outDir": "../../out-tsc/spec",
|
|
7
|
-
"types": [
|
|
8
|
-
"jasmine"
|
|
9
|
-
]
|
|
10
|
-
},
|
|
11
|
-
"include": [
|
|
12
|
-
"src/**/*.ts"
|
|
13
|
-
]
|
|
14
|
-
}
|
package/tools/generate-lib.js
DELETED
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import fs from "fs-extra"
|
|
3
|
-
import path from "path"
|
|
4
|
-
import { fileURLToPath } from 'url';
|
|
5
|
-
|
|
6
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
7
|
-
const __dirname = path.dirname(__filename);
|
|
8
|
-
/**
|
|
9
|
-
* Recursively replace all placeholders in files under a directory
|
|
10
|
-
* @param {string} srcDir - source directory path
|
|
11
|
-
* @param {Object.<string,string>} placeholders - map of placeholder -> value
|
|
12
|
-
*/
|
|
13
|
-
async function replacePlaceholdersInDir(srcDir, placeholders) {
|
|
14
|
-
const entries = await fs.readdir(srcDir, { withFileTypes: true });
|
|
15
|
-
for (const entry of entries) {
|
|
16
|
-
const fullPath = path.join(srcDir, entry.name);
|
|
17
|
-
if (entry.isDirectory()) {
|
|
18
|
-
await replacePlaceholdersInDir(fullPath, placeholders);
|
|
19
|
-
} else if (entry.isFile()) {
|
|
20
|
-
let content = await fs.readFile(fullPath, 'utf8');
|
|
21
|
-
for (const [key, value] of Object.entries(placeholders)) {
|
|
22
|
-
const regex = new RegExp(key, 'g');
|
|
23
|
-
content = content.replace(regex, value);
|
|
24
|
-
}
|
|
25
|
-
await fs.writeFile(fullPath, content);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Generate a new Angular library from template
|
|
32
|
-
* @param {string} libName - folder and project name
|
|
33
|
-
* @param {string} packageName - NPM package name (e.g. @org/lib)
|
|
34
|
-
* @param {string} version - initial version for the package
|
|
35
|
-
* @param {string} urlRegistry - NPM registry url
|
|
36
|
-
*/
|
|
37
|
-
async function generate(libName, packageName, version, urlRegistry) {
|
|
38
|
-
const tplDir = path.resolve(__dirname, '../templates/_lib_template');
|
|
39
|
-
const workspaceRoot = process.cwd();
|
|
40
|
-
const targetDir = path.resolve(workspaceRoot, 'projects', libName);
|
|
41
|
-
|
|
42
|
-
// 1) Copy the template directory
|
|
43
|
-
await fs.copy(tplDir, targetDir);
|
|
44
|
-
|
|
45
|
-
// 2) Replace placeholders __LIB_NAME__, __PACKAGE_NAME__, __VERSION__
|
|
46
|
-
const placeholders = {
|
|
47
|
-
'__LIB_NAME__': libName,
|
|
48
|
-
'__PACKAGE_NAME__': packageName,
|
|
49
|
-
'__VERSION__': version
|
|
50
|
-
};
|
|
51
|
-
await replacePlaceholdersInDir(targetDir, placeholders);
|
|
52
|
-
|
|
53
|
-
// 3) Update the library's package.json
|
|
54
|
-
const libPackageJsonPath = path.join(targetDir, 'package.json');
|
|
55
|
-
if (await fs.pathExists(libPackageJsonPath)) {
|
|
56
|
-
const libPkg = await fs.readJson(libPackageJsonPath);
|
|
57
|
-
libPkg.name = packageName;
|
|
58
|
-
libPkg.version = version;
|
|
59
|
-
if (urlRegistry) {
|
|
60
|
-
libPkg.publishConfig = {...(libPkg.publishConfig || {}), registry: urlRegistry};
|
|
61
|
-
} else if (libPkg.publishConfig?.registry) {
|
|
62
|
-
delete libPkg.publishConfig.registry;
|
|
63
|
-
if (Object.keys(libPkg.publishConfig).length === 0) delete libPkg.publishConfig;
|
|
64
|
-
}
|
|
65
|
-
await fs.writeJson(libPackageJsonPath, libPkg, { spaces: 2 });
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// 4) Update angular.json
|
|
69
|
-
const angularJsonPath = path.resolve(workspaceRoot, 'angular.json');
|
|
70
|
-
const ng = await fs.readJson(angularJsonPath);
|
|
71
|
-
|
|
72
|
-
ng.projects[libName] = {
|
|
73
|
-
root: `projects/${libName}`,
|
|
74
|
-
sourceRoot: `projects/${libName}/src`,
|
|
75
|
-
projectType: 'library',
|
|
76
|
-
"architect": {
|
|
77
|
-
"build": {
|
|
78
|
-
"builder": "@angular/build:ng-packagr",
|
|
79
|
-
"configurations": {
|
|
80
|
-
"production": {
|
|
81
|
-
"tsConfig": `projects/${libName}/tsconfig.lib.prod.json`
|
|
82
|
-
},
|
|
83
|
-
"development": {
|
|
84
|
-
"tsConfig": `projects/${libName}/tsconfig.lib.json`
|
|
85
|
-
}
|
|
86
|
-
},
|
|
87
|
-
"defaultConfiguration": "production"
|
|
88
|
-
},
|
|
89
|
-
"test": {
|
|
90
|
-
"builder": "@angular/build:karma",
|
|
91
|
-
"options": {
|
|
92
|
-
"tsConfig": `projects/${libName}/tsconfig.spec.json`
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
};
|
|
97
|
-
await fs.writeJson(angularJsonPath, ng, { spaces: 2 });
|
|
98
|
-
|
|
99
|
-
console.log(`✅ Library '${libName}' generated at projects/${libName}` +
|
|
100
|
-
` with package '${packageName}@${version}'`);
|
|
101
|
-
|
|
102
|
-
const ngPackagrPkg = findUpNodeModulePackageJson(workspaceRoot, 'ng-packagr');
|
|
103
|
-
if (!ngPackagrPkg) {
|
|
104
|
-
console.warn(
|
|
105
|
-
[
|
|
106
|
-
"⚠️ 'ng-packagr' n'est pas installé dans ce workspace.",
|
|
107
|
-
" Pour builder une librairie (ng-packagr), installez-le dans votre projet Angular :",
|
|
108
|
-
" npm i -D ng-packagr",
|
|
109
|
-
].join('\n')
|
|
110
|
-
);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
function findUpNodeModulePackageJson(startDir, packageName) {
|
|
115
|
-
let dir = startDir;
|
|
116
|
-
while (true) {
|
|
117
|
-
const candidate = path.join(dir, 'node_modules', packageName, 'package.json');
|
|
118
|
-
if (fs.existsSync(candidate)) return candidate;
|
|
119
|
-
const parent = path.dirname(dir);
|
|
120
|
-
if (parent === dir) return undefined;
|
|
121
|
-
dir = parent;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// CLI args: node generate-lib.js <lib-name> <package-name> [version] <url-registry>
|
|
126
|
-
// CLI args: node generate-lib.js <lib-name> <package-name> [version] [url-registry]
|
|
127
|
-
const [,, libName, packageName, version = '0.0.1', urlRegistry] = process.argv;
|
|
128
|
-
if (!libName || !packageName) {
|
|
129
|
-
console.error('Usage: generate-lib.js <lib-name> <package-name> [version] [url-registry]');
|
|
130
|
-
process.exit(1);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
generate(libName, packageName, version, urlRegistry).catch(err => {
|
|
134
|
-
console.error(err);
|
|
135
|
-
process.exit(1);
|
|
136
|
-
});
|
package/tools/generate-models.js
DELETED
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import fs from 'node:fs/promises';
|
|
4
|
-
import process from 'node:process';
|
|
5
|
-
import {fileURLToPath, pathToFileURL} from 'node:url';
|
|
6
|
-
|
|
7
|
-
import {renderTemplateToFile} from './generator/models/handlebars.js';
|
|
8
|
-
import {buildModelsFromOpenAPI} from './generator/models/openapi-to-models.js';
|
|
9
|
-
import {ensureCleanDir} from './generator/models/utils.js';
|
|
10
|
-
|
|
11
|
-
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Récupère un argument CLI de la forme --name=value
|
|
15
|
-
* @param {string} name
|
|
16
|
-
* @param {string|undefined} def
|
|
17
|
-
* @returns {string|undefined}
|
|
18
|
-
*/
|
|
19
|
-
function getArg(name, def) {
|
|
20
|
-
const a = process.argv.find((x) => x.startsWith(`--${name}=`));
|
|
21
|
-
return a ? a.split('=')[1] : def;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Lit la specification OpenAPI depuis une URL http(s) ou un chemin fichier JSON.
|
|
26
|
-
* @param {string} specPathOrUrl
|
|
27
|
-
*/
|
|
28
|
-
async function readSpec(specPathOrUrl) {
|
|
29
|
-
if (/^https?:\/\//.test(specPathOrUrl)) {
|
|
30
|
-
const res = await fetch(specPathOrUrl);
|
|
31
|
-
if (!res.ok) {
|
|
32
|
-
throw new Error(`Impossible de télécharger la spec : ${res.status} ${res.statusText}`);
|
|
33
|
-
}
|
|
34
|
-
return await res.json();
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
try {
|
|
38
|
-
const src = await fs.readFile(specPathOrUrl, 'utf8');
|
|
39
|
-
return JSON.parse(src);
|
|
40
|
-
} catch (err) {
|
|
41
|
-
if (err.code === 'ENOENT') {
|
|
42
|
-
throw new Error(`Fichier non trouvé : ${specPathOrUrl}`);
|
|
43
|
-
}
|
|
44
|
-
if (err.name === 'SyntaxError') {
|
|
45
|
-
throw new Error(`JSON invalide dans ${specPathOrUrl} : ${err.message}`);
|
|
46
|
-
}
|
|
47
|
-
throw err;
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* Charge un fichier de config local `models.config.js` (CWD) s'il existe.
|
|
52
|
-
* Le module peut exporter par défaut ou via export nommé.
|
|
53
|
-
*/
|
|
54
|
-
async function loadUserConfig() {
|
|
55
|
-
const cfgPath = path.resolve(process.cwd(), 'models.config.js');
|
|
56
|
-
try {
|
|
57
|
-
const st = await fs.stat(cfgPath);
|
|
58
|
-
if (!st.isFile()) return {};
|
|
59
|
-
const mod = await import(pathToFileURL(cfgPath).href);
|
|
60
|
-
return (mod?.default && typeof mod.default === 'object') ? mod.default : (mod || {});
|
|
61
|
-
} catch {
|
|
62
|
-
return {};
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
async function main() {
|
|
66
|
-
const specPathOrUrl = process.argv[2];
|
|
67
|
-
if (!specPathOrUrl) {
|
|
68
|
-
console.error('Usage: generate-models.js <OpenAPI spec (url|fichier)> [--item-import=../lib/ports/resource-repository.port] [--out=models] [--required-mode=all-optional|spec] [--no-index]');
|
|
69
|
-
process.exit(1);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
const workDir = process.cwd();
|
|
73
|
-
const userCfg = await loadUserConfig();
|
|
74
|
-
const outDir = path.resolve(workDir, getArg('out', userCfg.outDir || 'models'));
|
|
75
|
-
const writeIndex = !('' + process.argv.join(' ')).includes('--no-index');
|
|
76
|
-
const itemImportPath = getArg('item-import', userCfg.itemImportPath || '../lib/ports/resource-repository.port');
|
|
77
|
-
const requiredMode = (() => {
|
|
78
|
-
const v = getArg('required-mode', userCfg.requiredMode || 'all-optional');
|
|
79
|
-
return (v === 'spec' || v === 'all-optional') ? v : 'all-optional';
|
|
80
|
-
})();
|
|
81
|
-
const preferFlavor = userCfg.preferFlavor; // 'jsonld' | 'jsonapi' | 'none'
|
|
82
|
-
const hydraBaseRegex = userCfg.hydraBaseRegex; // RegExp|string
|
|
83
|
-
|
|
84
|
-
console.log(`📥 Spec OpenAPI: ${specPathOrUrl}`);
|
|
85
|
-
const spec = await readSpec(specPathOrUrl);
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
console.log('🔧 Construction des interfaces…');
|
|
89
|
-
const {models} = buildModelsFromOpenAPI(spec, { requiredMode, preferFlavor, hydraBaseRegex });
|
|
90
|
-
|
|
91
|
-
const templatesDir = path.join(__dirname, 'generator', 'models', 'templates');
|
|
92
|
-
await ensureCleanDir(outDir);
|
|
93
|
-
|
|
94
|
-
for (const m of models) {
|
|
95
|
-
await renderTemplateToFile({
|
|
96
|
-
templatePath: path.join(templatesDir, 'model.hbs'),
|
|
97
|
-
outPath: path.join(outDir, `${m.name}.ts`),
|
|
98
|
-
ctx: {
|
|
99
|
-
itemImportPath,
|
|
100
|
-
name: m.name,
|
|
101
|
-
props: m.props,
|
|
102
|
-
imports: m.imports,
|
|
103
|
-
},
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
if (writeIndex) {
|
|
108
|
-
await renderTemplateToFile({
|
|
109
|
-
templatePath: path.join(templatesDir, 'index.hbs'),
|
|
110
|
-
outPath: path.join(outDir, 'index.ts'),
|
|
111
|
-
ctx: {models: models.map((m) => ({name: m.name}))},
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
console.log(`✅ ${models.length} modèle(s) écrit(s) dans ${path.relative(workDir, outDir)}`);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
main().catch((err) => {
|
|
119
|
-
console.error(err);
|
|
120
|
-
process.exit(1);
|
|
121
|
-
});
|