@obsidiane/meridiane 0.0.7 → 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.
@@ -1,175 +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
- import {asBool, getArg, getArgs} from './utils/cli-args.js';
11
- import {loadDotEnv} from './utils/dotenv.js';
12
-
13
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
14
-
15
- /**
16
- * Lit la specification OpenAPI depuis une URL http(s) ou un chemin fichier JSON.
17
- * @param {string} specPathOrUrl
18
- */
19
- async function readSpec(specPathOrUrl) {
20
- if (/^https?:\/\//.test(specPathOrUrl)) {
21
- const res = await fetch(specPathOrUrl);
22
- if (!res.ok) {
23
- throw new Error(`Impossible de télécharger la spec : ${res.status} ${res.statusText}`);
24
- }
25
- return await res.json();
26
- }
27
-
28
- try {
29
- const src = await fs.readFile(specPathOrUrl, 'utf8');
30
- return JSON.parse(src);
31
- } catch (err) {
32
- if (err.code === 'ENOENT') {
33
- throw new Error(`Fichier non trouvé : ${specPathOrUrl}`);
34
- }
35
- if (err.name === 'SyntaxError') {
36
- throw new Error(`JSON invalide dans ${specPathOrUrl} : ${err.message}`);
37
- }
38
- throw err;
39
- }
40
- }
41
- /**
42
- * Charge un fichier de config local `models.config.js` (CWD) s'il existe.
43
- * Le module peut exporter par défaut ou via export nommé.
44
- */
45
- async function loadUserConfig() {
46
- const cfgPath = await findUp(process.cwd(), 'models.config.js');
47
- try {
48
- if (!cfgPath) return {};
49
- const st = await fs.stat(cfgPath);
50
- if (!st.isFile()) return {};
51
- const mod = await import(pathToFileURL(cfgPath).href);
52
- const cfg = mod?.default ?? mod;
53
- return (cfg && typeof cfg === 'object') ? cfg : {};
54
- } catch {
55
- return {};
56
- }
57
- }
58
-
59
- async function findUp(startDir, fileName) {
60
- let dir = startDir;
61
- while (true) {
62
- const candidate = path.join(dir, fileName);
63
- try {
64
- const st = await fs.stat(candidate);
65
- if (st.isFile()) return candidate;
66
- } catch {
67
- // ignore
68
- }
69
- const parent = path.dirname(dir);
70
- if (parent === dir) return undefined;
71
- dir = parent;
72
- }
73
- }
74
- async function main() {
75
- await loadDotEnv();
76
- const debug = process.argv.includes('--debug') || /^(1|true|yes)$/i.test(process.env.MERIDIANE_DEBUG ?? '');
77
-
78
- const specPathOrUrl = process.argv[2];
79
- if (!specPathOrUrl) {
80
- console.error('Usage: generate-models.js <OpenAPI spec (url|fichier)> [--item-import=../lib/ports/resource-repository.port] [--out=models] [--required-mode=all-optional|spec] [--preset=all|native] [--include=<substr>] [--exclude=<substr>] [--index=1|0]');
81
- process.exit(1);
82
- }
83
-
84
- const workDir = process.cwd();
85
- const userCfg = await loadUserConfig();
86
- const outDir = path.resolve(workDir, getArg('out', userCfg.outDir || process.env.MERIDIANE_MODELS_OUT || 'models'));
87
- const writeIndex = (() => {
88
- const cli = getArg('index', undefined);
89
- if (typeof cli === 'string') return asBool(cli, true);
90
- if (typeof userCfg.writeIndex === 'boolean') return userCfg.writeIndex;
91
- return asBool(process.env.MERIDIANE_MODELS_INDEX ?? '1', true);
92
- })();
93
- const itemImportPath = getArg(
94
- 'item-import',
95
- userCfg.itemImportPath || process.env.MERIDIANE_MODELS_ITEM_IMPORT || '../lib/ports/resource-repository.port'
96
- );
97
- const requiredMode = (() => {
98
- const v = getArg('required-mode', userCfg.requiredMode || process.env.MERIDIANE_MODELS_REQUIRED_MODE || 'all-optional');
99
- return (v === 'spec' || v === 'all-optional') ? v : 'all-optional';
100
- })();
101
- const preset = (() => {
102
- const v = getArg('preset', userCfg.preset || process.env.MERIDIANE_MODELS_PRESET || 'all');
103
- return (v === 'native' || v === 'all') ? v : 'all';
104
- })();
105
- const preferFlavor = userCfg.preferFlavor; // 'jsonld' | 'jsonapi' | 'none'
106
- const hydraBaseRegex = userCfg.hydraBaseRegex; // RegExp|string
107
- const includeCli = getArgs('include').flatMap((v) => v.split(',').map((s) => s.trim()).filter(Boolean));
108
- const excludeCli = getArgs('exclude').flatMap((v) => v.split(',').map((s) => s.trim()).filter(Boolean));
109
- const includeSchemaNames = [
110
- ...(Array.isArray(userCfg.includeSchemaNames) ? userCfg.includeSchemaNames : []),
111
- ...includeCli,
112
- ];
113
- const excludeSchemaNames = [
114
- ...(Array.isArray(userCfg.excludeSchemaNames) ? userCfg.excludeSchemaNames : []),
115
- ...excludeCli,
116
- ];
117
-
118
- if (debug) {
119
- console.log('[meridiane models] debug', {
120
- outDir: path.relative(workDir, outDir),
121
- writeIndex,
122
- itemImportPath,
123
- requiredMode,
124
- preset,
125
- preferFlavor,
126
- includeCount: includeSchemaNames.length,
127
- excludeCount: excludeSchemaNames.length,
128
- });
129
- }
130
-
131
- console.log(`📥 Spec OpenAPI: ${specPathOrUrl}`);
132
- const spec = await readSpec(specPathOrUrl);
133
-
134
-
135
- console.log('🔧 Construction des interfaces…');
136
- const {models} = buildModelsFromOpenAPI(spec, {
137
- requiredMode,
138
- preset,
139
- preferFlavor,
140
- hydraBaseRegex,
141
- includeSchemaNames,
142
- excludeSchemaNames,
143
- });
144
-
145
- const templatesDir = path.join(__dirname, 'generator', 'models', 'templates');
146
- await ensureCleanDir(outDir);
147
-
148
- for (const m of models) {
149
- await renderTemplateToFile({
150
- templatePath: path.join(templatesDir, 'model.hbs'),
151
- outPath: path.join(outDir, `${m.name}.ts`),
152
- ctx: {
153
- itemImportPath,
154
- name: m.name,
155
- props: m.props,
156
- imports: m.imports,
157
- },
158
- });
159
- }
160
-
161
- if (writeIndex) {
162
- await renderTemplateToFile({
163
- templatePath: path.join(templatesDir, 'index.hbs'),
164
- outPath: path.join(outDir, 'index.ts'),
165
- ctx: {models: models.map((m) => ({name: m.name}))},
166
- });
167
- }
168
-
169
- console.log(`✅ ${models.length} modèle(s) écrit(s) dans ${path.relative(workDir, outDir)}`);
170
- }
171
-
172
- main().catch((err) => {
173
- console.error(err);
174
- process.exit(1);
175
- });
package/tools/init.js DELETED
@@ -1,148 +0,0 @@
1
- #!/usr/bin/env node
2
- import path from 'node:path';
3
- import process from 'node:process';
4
- import {fileURLToPath} from 'node:url';
5
- import fs from 'node:fs/promises';
6
-
7
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
8
-
9
- function hasFlag(name) {
10
- return process.argv.includes(`--${name}`);
11
- }
12
-
13
- async function pathExists(p) {
14
- try {
15
- await fs.stat(p);
16
- return true;
17
- } catch {
18
- return false;
19
- }
20
- }
21
-
22
- async function ensureDir(p) {
23
- await fs.mkdir(p, {recursive: true});
24
- }
25
-
26
- async function writeFileIfMissing(filePath, content, {force} = {}) {
27
- const exists = await pathExists(filePath);
28
- if (exists && !force) return {written: false, reason: 'exists'};
29
- await ensureDir(path.dirname(filePath));
30
- await fs.writeFile(filePath, content, 'utf8');
31
- return {written: true};
32
- }
33
-
34
- async function copyFileIfMissing(src, dest, {force} = {}) {
35
- const exists = await pathExists(dest);
36
- if (exists && !force) return {written: false, reason: 'exists'};
37
- await ensureDir(path.dirname(dest));
38
- await fs.copyFile(src, dest);
39
- return {written: true};
40
- }
41
-
42
- async function main() {
43
- const force = hasFlag('force');
44
- const debug = /^(1|true|yes)$/i.test(process.env.MERIDIANE_DEBUG ?? '') || hasFlag('debug');
45
-
46
- const cwd = process.cwd();
47
- const pkgRoot = path.resolve(__dirname, '..');
48
-
49
- const outDir = path.resolve(cwd, 'meridiane');
50
- await ensureDir(outDir);
51
-
52
- const modelsExample = path.join(pkgRoot, 'models.config.example.js');
53
- const modelsOut = path.resolve(cwd, 'models.config.js');
54
- const envExampleOut = path.resolve(cwd, '.env.example');
55
-
56
- const angularExampleOut = path.join(outDir, 'angular.example.ts');
57
- const readmeOut = path.join(outDir, 'README.md');
58
-
59
- if (debug) console.log('[meridiane init] cwd=', cwd);
60
-
61
- const copiedCfg = await copyFileIfMissing(modelsExample, modelsOut, {force});
62
- const wroteEnv = await writeFileIfMissing(
63
- envExampleOut,
64
- [
65
- '# Meridiane (CLI) - exemple de configuration',
66
- '# Copiez en `.env` pour activer la config locale.',
67
- '',
68
- '# Logs',
69
- 'MERIDIANE_DEBUG=0',
70
- '',
71
- '# meridiane lib',
72
- '# MERIDIANE_LIB_VERSION=0.1.0',
73
- '# MERIDIANE_NPM_REGISTRY_URL=https://registry.npmjs.org/',
74
- '',
75
- '# meridiane models',
76
- '# MERIDIANE_MODELS_OUT=projects/backend-bridge/src/models',
77
- '# MERIDIANE_MODELS_REQUIRED_MODE=spec',
78
- '# MERIDIANE_MODELS_ITEM_IMPORT=../lib/ports/resource-repository.port',
79
- '# MERIDIANE_MODELS_PRESET=all',
80
- '# MERIDIANE_MODELS_INDEX=1',
81
- '',
82
- '# Runtime (Angular) - à recopier dans provideBridge(...)',
83
- '# MERIDIANE_API_BASE_URL=http://localhost:8000',
84
- '# MERIDIANE_MERCURE_HUB_URL=http://localhost:8000/.well-known/mercure',
85
- '',
86
- ].join('\n'),
87
- {force}
88
- );
89
-
90
- const wroteAngular = await writeFileIfMissing(
91
- angularExampleOut,
92
- [
93
- "import {provideBridge} from '@acme/backend-bridge';",
94
- '',
95
- 'export const BRIDGE_PROVIDERS = [',
96
- ' provideBridge({',
97
- " baseUrl: 'http://localhost:8000',",
98
- ' mercure: {',
99
- " hubUrl: 'http://localhost:8000/.well-known/mercure',",
100
- " init: {credentials: 'include'},",
101
- ' },',
102
- ' defaults: {',
103
- ' headers: {',
104
- " // 'X-Correlation-Id': crypto.randomUUID(),",
105
- ' },',
106
- ' timeoutMs: 30_000,',
107
- ' retries: {count: 1, delayMs: 250},',
108
- ' },',
109
- ' // auth: {type: \"bearer\", token: \"<JWT>\"},',
110
- ' debug: false,',
111
- ' }),',
112
- '];',
113
- '',
114
- ].join('\n'),
115
- {force}
116
- );
117
-
118
- const wroteReadme = await writeFileIfMissing(
119
- readmeOut,
120
- [
121
- '# Meridiane – fichiers générés',
122
- '',
123
- 'Ces fichiers sont créés par `meridiane init` pour accélérer l’intégration.',
124
- '',
125
- '## CLI',
126
- '',
127
- '- `models.config.js` : configuration par défaut de `meridiane models` (chargée depuis le CWD).',
128
- "- `.env` : optionnel. Le CLI charge automatiquement `.env` (CWD) avant d'exécuter `lib/models`.",
129
- '',
130
- '## Angular',
131
- '',
132
- '- `angular.example.ts` : exemple `provideBridge({ baseUrl, mercure, defaults, auth, debug })` à adapter.',
133
- '',
134
- ].join('\n'),
135
- {force}
136
- );
137
-
138
- console.log('✅ meridiane init');
139
- console.log(`- ${path.relative(cwd, modelsOut)} ${copiedCfg.written ? 'créé' : '(existe déjà)'}`);
140
- console.log(`- ${path.relative(cwd, envExampleOut)} ${wroteEnv.written ? 'créé' : '(existe déjà)'}`);
141
- console.log(`- ${path.relative(cwd, angularExampleOut)} ${wroteAngular.written ? 'créé' : '(existe déjà)'}`);
142
- console.log(`- ${path.relative(cwd, readmeOut)} ${wroteReadme.written ? 'créé' : '(existe déjà)'}`);
143
- }
144
-
145
- main().catch((err) => {
146
- console.error(err);
147
- process.exit(1);
148
- });
@@ -1,77 +0,0 @@
1
- #!/usr/bin/env node
2
- import path from 'node:path';
3
- import process from 'node:process';
4
- import {fileURLToPath} from 'node:url';
5
- import {spawn} from 'node:child_process';
6
- import {loadDotEnv} from './utils/dotenv.js';
7
- import {getArg, hasFlag} from './utils/cli-args.js';
8
-
9
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
10
- const repoRoot = path.resolve(__dirname, '../../..');
11
-
12
- function run(args) {
13
- return new Promise((resolve) => {
14
- const child = spawn(process.execPath, args, {stdio: 'inherit', env: process.env});
15
- child.on('exit', (code) => resolve(code ?? 0));
16
- });
17
- }
18
-
19
- function printHelp() {
20
- console.log(`
21
- Usage:
22
- meridiane sandbox-bridge [options]
23
-
24
- This command regenerates the Angular bridge library used by the sandbox:
25
- - workspace: apps/sandbox
26
- - libName: bridge-sandbox
27
- - package: @obsidiane/bridge-sandbox
28
- - version: 0.1.0 (override with --version)
29
-
30
- Options:
31
- --backend=http://localhost:8000
32
- --spec=/api/docs.json
33
- --models-out=projects/bridge-sandbox/src/models
34
- --required-mode=all-optional|spec
35
- --preset=all|native
36
- --include=<substr>[,<substr>…] (repeatable)
37
- --exclude=<substr>[,<substr>…] (repeatable)
38
- --index=1|0
39
- --no-models
40
- --debug
41
-
42
- Example:
43
- npx -y @obsidiane/meridiane sandbox-bridge --backend=http://localhost:8000
44
- `);
45
- }
46
-
47
- async function main() {
48
- await loadDotEnv();
49
-
50
- if (hasFlag('help') || hasFlag('h')) {
51
- printHelp();
52
- process.exit(0);
53
- }
54
-
55
- const version = getArg('version', process.env.MERIDIANE_SANDBOX_BRIDGE_VERSION ?? '0.1.0');
56
-
57
- const passThrough = process.argv.slice(2).filter((a) => a.startsWith('--') && !a.startsWith('--version='));
58
-
59
- const devBridgePath = path.join(__dirname, 'dev-bridge.js');
60
- const workspaceAbs = path.join(repoRoot, 'apps', 'sandbox');
61
- const args = [
62
- devBridgePath,
63
- 'bridge-sandbox',
64
- '@obsidiane/bridge-sandbox',
65
- version,
66
- `--workspace=${workspaceAbs}`,
67
- ...passThrough,
68
- ];
69
-
70
- const code = await run(args);
71
- process.exit(code);
72
- }
73
-
74
- main().catch((err) => {
75
- console.error(err);
76
- process.exit(1);
77
- });
@@ -1,41 +0,0 @@
1
- /**
2
- * @param {string} name
3
- * @param {string|undefined} def
4
- * @param {string[]} [argv]
5
- * @returns {string|undefined}
6
- */
7
- export function getArg(name, def, argv = process.argv) {
8
- const a = argv.find((x) => x.startsWith(`--${name}=`));
9
- return a ? a.split('=')[1] : def;
10
- }
11
-
12
- /**
13
- * @param {string} name
14
- * @param {string[]} [argv]
15
- * @returns {string[]}
16
- */
17
- export function getArgs(name, argv = process.argv) {
18
- return argv
19
- .filter((x) => x.startsWith(`--${name}=`))
20
- .map((x) => x.slice(`--${name}=`.length));
21
- }
22
-
23
- /**
24
- * @param {string} name
25
- * @param {string[]} [argv]
26
- */
27
- export function hasFlag(name, argv = process.argv) {
28
- return argv.includes(`--${name}`);
29
- }
30
-
31
- /**
32
- * @param {unknown} v
33
- * @param {boolean} def
34
- */
35
- export function asBool(v, def) {
36
- if (typeof v !== 'string') return def;
37
- if (/^(1|true|yes)$/i.test(v)) return true;
38
- if (/^(0|false|no)$/i.test(v)) return false;
39
- return def;
40
- }
41
-
@@ -1,55 +0,0 @@
1
- import fs from 'node:fs/promises';
2
- import path from 'node:path';
3
-
4
- /**
5
- * Charge un fichier `.env` (format KEY=VALUE) dans process.env, sans écraser les variables déjà définies.
6
- * @param {{cwd?: string, filename?: string}} [opts]
7
- * @returns {Promise<Record<string, string>>} variables chargées
8
- */
9
- export async function loadDotEnv(opts = {}) {
10
- const cwd = opts.cwd ?? process.cwd();
11
- const filename = opts.filename ?? '.env';
12
- const envPath = await findUp(cwd, filename);
13
- if (!envPath) return {};
14
-
15
- const raw = await fs.readFile(envPath, 'utf8');
16
-
17
- const loaded = {};
18
- for (const line of raw.split(/\r?\n/)) {
19
- const trimmed = line.trim();
20
- if (!trimmed || trimmed.startsWith('#')) continue;
21
- const normalized = trimmed.startsWith('export ') ? trimmed.slice('export '.length).trim() : trimmed;
22
- const idx = normalized.indexOf('=');
23
- if (idx < 0) continue;
24
- const key = normalized.slice(0, idx).trim();
25
- let value = normalized.slice(idx + 1).trim();
26
- if (!key) continue;
27
-
28
- if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) {
29
- value = value.slice(1, -1);
30
- }
31
-
32
- if (process.env[key] === undefined) {
33
- process.env[key] = value;
34
- loaded[key] = value;
35
- }
36
- }
37
-
38
- return loaded;
39
- }
40
-
41
- async function findUp(startDir, fileName) {
42
- let dir = startDir;
43
- while (true) {
44
- const candidate = path.join(dir, fileName);
45
- try {
46
- const st = await fs.stat(candidate);
47
- if (st.isFile()) return candidate;
48
- } catch {
49
- // ignore
50
- }
51
- const parent = path.dirname(dir);
52
- if (parent === dir) return undefined;
53
- dir = parent;
54
- }
55
- }