@contentstorage/core 0.3.28 → 0.3.30
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/dist/contentstorage-config.d.ts +3 -0
- package/dist/contentstorage-config.js +3 -0
- package/dist/helpers/defineConfig.d.ts +6 -0
- package/dist/helpers/defineConfig.js +19 -0
- package/dist/helpers/flattenJson.js +0 -2
- package/dist/index.js +1 -1
- package/dist/lib/configLoader.js +4 -5
- package/dist/lib/contentManagement.d.ts +1 -1
- package/dist/lib/contentManagement.js +7 -4
- package/dist/scripts/generate-types.js +12 -16
- package/dist/scripts/pull-content.js +5 -4
- package/dist/types.d.ts +3 -3
- package/package.json +1 -1
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helper function to define your application configuration.
|
|
3
|
+
* Provides autocompletion and type-checking for contentstorage.config.js files.
|
|
4
|
+
*/
|
|
5
|
+
export function defineConfig(config) {
|
|
6
|
+
// You can add basic runtime validation here if desired,
|
|
7
|
+
// e.g., check if contentUrl is a valid URL format,
|
|
8
|
+
// or if languageCodes is not empty.
|
|
9
|
+
if (!config.languageCodes || config.languageCodes.length === 0) {
|
|
10
|
+
console.warn('Warning: languageCodes array is empty or missing in the configuration.');
|
|
11
|
+
}
|
|
12
|
+
if (!config.contentDir) {
|
|
13
|
+
// This would typically be a hard error, but defineConfig is more for type safety at edit time.
|
|
14
|
+
// Runtime validation (see point 3) is better for hard errors.
|
|
15
|
+
console.warn('Warning: contentDir is missing in the configuration.');
|
|
16
|
+
}
|
|
17
|
+
// ... other checks
|
|
18
|
+
return config;
|
|
19
|
+
}
|
|
@@ -31,7 +31,6 @@ export function flattenJson(data, prefix = '', result = {}) {
|
|
|
31
31
|
});
|
|
32
32
|
}
|
|
33
33
|
else {
|
|
34
|
-
// It's an object (and not a special one that stops flattening, due to the preceding 'if' block)
|
|
35
34
|
let isEmptyObject = true;
|
|
36
35
|
for (const key in data) {
|
|
37
36
|
if (Object.prototype.hasOwnProperty.call(data, key)) {
|
|
@@ -48,7 +47,6 @@ export function flattenJson(data, prefix = '', result = {}) {
|
|
|
48
47
|
}
|
|
49
48
|
}
|
|
50
49
|
else if (prefix) {
|
|
51
|
-
// Primitive value (string, number, boolean, null) and has a prefix
|
|
52
50
|
result[prefix] = data;
|
|
53
51
|
}
|
|
54
52
|
// If the initial data is a primitive and prefix is empty, result remains empty.
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { setContentLanguage, getText, getImage, getVariation } from './lib/contentManagement.js';
|
|
1
|
+
import { setContentLanguage, getText, getImage, getVariation, } from './lib/contentManagement.js';
|
|
2
2
|
export { setContentLanguage, getText, getImage, getVariation };
|
package/dist/lib/configLoader.js
CHANGED
|
@@ -32,14 +32,13 @@ export async function loadConfig() {
|
|
|
32
32
|
...userConfig,
|
|
33
33
|
};
|
|
34
34
|
// Validate required fields
|
|
35
|
-
if (!mergedConfig.
|
|
36
|
-
console.error('Error: Configuration is missing the required "
|
|
37
|
-
process.exit(1);
|
|
35
|
+
if (!mergedConfig.contentKey) {
|
|
36
|
+
console.error('Error: Configuration is missing the required "contentKey" property.');
|
|
37
|
+
process.exit(1);
|
|
38
38
|
}
|
|
39
|
-
// Resolve paths relative to the user's project root (process.cwd())
|
|
40
39
|
const finalConfig = {
|
|
41
40
|
languageCodes: mergedConfig.languageCodes || [],
|
|
42
|
-
|
|
41
|
+
contentKey: mergedConfig.contentKey,
|
|
43
42
|
contentDir: path.resolve(process.cwd(), mergedConfig.contentDir),
|
|
44
43
|
typesOutputFile: path.resolve(process.cwd(), mergedConfig.typesOutputFile),
|
|
45
44
|
};
|
|
@@ -2,7 +2,7 @@ import { ContentStructure, ImageObject } from '../types.js';
|
|
|
2
2
|
/**
|
|
3
3
|
* Loads and sets the content for a specific language.
|
|
4
4
|
* It will internally ensure the application configuration (for contentDir) is loaded.
|
|
5
|
-
* @param
|
|
5
|
+
* @param contentJson
|
|
6
6
|
*/
|
|
7
7
|
export declare function setContentLanguage(contentJson: object): void;
|
|
8
8
|
/**
|
|
@@ -2,11 +2,11 @@ let activeContent = null;
|
|
|
2
2
|
/**
|
|
3
3
|
* Loads and sets the content for a specific language.
|
|
4
4
|
* It will internally ensure the application configuration (for contentDir) is loaded.
|
|
5
|
-
* @param
|
|
5
|
+
* @param contentJson
|
|
6
6
|
*/
|
|
7
7
|
export function setContentLanguage(contentJson) {
|
|
8
8
|
if (!contentJson || typeof contentJson !== 'object') {
|
|
9
|
-
throw new Error('[Contentstorage] Invalid
|
|
9
|
+
throw new Error('[Contentstorage] Invalid contentKey might be provided which caused setContentLanguage to fail.');
|
|
10
10
|
}
|
|
11
11
|
try {
|
|
12
12
|
activeContent = contentJson; // Relies on augmentation
|
|
@@ -109,7 +109,9 @@ export function getVariation(pathString, variationKey, fallbackString) {
|
|
|
109
109
|
typeof current.data === 'object' &&
|
|
110
110
|
current.data !== null) {
|
|
111
111
|
const variationObject = current;
|
|
112
|
-
if (variationKey &&
|
|
112
|
+
if (variationKey &&
|
|
113
|
+
typeof variationKey === 'string' &&
|
|
114
|
+
variationKey in variationObject.data) {
|
|
113
115
|
if (typeof variationObject.data[variationKey] === 'string') {
|
|
114
116
|
return variationObject.data[variationKey];
|
|
115
117
|
}
|
|
@@ -121,7 +123,8 @@ export function getVariation(pathString, variationKey, fallbackString) {
|
|
|
121
123
|
// If specific variationKey is not found or not provided, try to return the 'default' variation
|
|
122
124
|
if ('default' in variationObject.data && typeof variationKey === 'string') {
|
|
123
125
|
if (typeof variationObject.data.default === 'string') {
|
|
124
|
-
if (variationKey && variationKey !== 'default') {
|
|
126
|
+
if (variationKey && variationKey !== 'default') {
|
|
127
|
+
// Warn if specific key was requested but default is being returned
|
|
125
128
|
const msg = `[Contentstorage] getVariation: Variation key "${variationKey}" not found at path "${pathString}". Returning 'default' variation.`;
|
|
126
129
|
console.warn(msg);
|
|
127
130
|
}
|
|
@@ -7,6 +7,7 @@ import jsonToTS from 'json-to-ts'; // Import the library
|
|
|
7
7
|
import chalk from 'chalk'; // Optional: for colored output
|
|
8
8
|
import { loadConfig } from '../lib/configLoader.js';
|
|
9
9
|
import { flattenJson } from '../helpers/flattenJson.js';
|
|
10
|
+
import { CONTENTSTORAGE_CONFIG } from '../contentstorage-config.js';
|
|
10
11
|
export async function generateTypes() {
|
|
11
12
|
console.log(chalk.blue('Starting type generation...'));
|
|
12
13
|
const config = await loadConfig();
|
|
@@ -20,7 +21,7 @@ export async function generateTypes() {
|
|
|
20
21
|
console.error(chalk.red.bold("Configuration error: 'languageCodes' must be a non-empty array."));
|
|
21
22
|
process.exit(1);
|
|
22
23
|
}
|
|
23
|
-
console.log(chalk.
|
|
24
|
+
console.log(chalk.blue(`TypeScript types will be saved to: ${config.typesOutputFile}`));
|
|
24
25
|
let jsonObject; // To hold the JSON data from either local or remote source
|
|
25
26
|
let dataSourceDescription = ''; // For clearer logging
|
|
26
27
|
const firstLanguageCode = config.languageCodes[0];
|
|
@@ -30,7 +31,7 @@ export async function generateTypes() {
|
|
|
30
31
|
try {
|
|
31
32
|
await fs.stat(config.contentDir); // Check if directory exists
|
|
32
33
|
attemptLocalLoad = true;
|
|
33
|
-
console.log(chalk.
|
|
34
|
+
console.log(chalk.blue(`Local content directory found: ${config.contentDir}`));
|
|
34
35
|
}
|
|
35
36
|
catch (statError) {
|
|
36
37
|
if (statError.code === 'ENOENT') {
|
|
@@ -51,12 +52,12 @@ export async function generateTypes() {
|
|
|
51
52
|
const targetFilename = `${firstLanguageCode}.json`;
|
|
52
53
|
const jsonFilePath = path.join(config.contentDir, targetFilename);
|
|
53
54
|
dataSourceDescription = `local file (${jsonFilePath})`;
|
|
54
|
-
console.log(chalk.
|
|
55
|
+
console.log(chalk.blue(`Attempting to read JSON from: ${jsonFilePath}`));
|
|
55
56
|
try {
|
|
56
57
|
const jsonContentString = await fs.readFile(jsonFilePath, 'utf-8');
|
|
57
|
-
console.log(chalk.
|
|
58
|
+
console.log(chalk.blue('Parsing JSON'));
|
|
58
59
|
const parsendJsonObject = JSON.parse(jsonContentString);
|
|
59
|
-
console.log(chalk.
|
|
60
|
+
console.log(chalk.blue('Flattening JSON for type generation'));
|
|
60
61
|
jsonObject = flattenJson(parsendJsonObject);
|
|
61
62
|
console.log(chalk.green(`Successfully read and parsed JSON from ${jsonFilePath}.`));
|
|
62
63
|
}
|
|
@@ -70,17 +71,16 @@ export async function generateTypes() {
|
|
|
70
71
|
}
|
|
71
72
|
}
|
|
72
73
|
else {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
throw new Error("Cannot generate types: 'contentDir' is not accessible or not specified, and 'contentUrl' is also missing in configuration.");
|
|
74
|
+
if (!config.contentKey) {
|
|
75
|
+
throw new Error('Cannot generate types: contentKey is missing');
|
|
76
76
|
}
|
|
77
|
-
const fileUrl = `${config.
|
|
77
|
+
const fileUrl = `${CONTENTSTORAGE_CONFIG.BASE_URL}/${config.contentKey}/content/${firstLanguageCode}.json`; // Adjust URL construction if necessary
|
|
78
78
|
dataSourceDescription = `remote URL (${fileUrl})`;
|
|
79
|
-
console.log(chalk.
|
|
79
|
+
console.log(chalk.blue(`Attempting to fetch JSON from: ${fileUrl}`));
|
|
80
80
|
try {
|
|
81
81
|
const response = await axios.get(fileUrl, { responseType: 'json' });
|
|
82
82
|
const jsonResponse = response.data;
|
|
83
|
-
console.log(chalk.
|
|
83
|
+
console.log(chalk.blue('Flattening JSON for type generation'));
|
|
84
84
|
jsonObject = flattenJson(jsonResponse);
|
|
85
85
|
if (typeof jsonObject !== 'object' || jsonObject === null) {
|
|
86
86
|
throw new Error(`Workspaceed data from ${fileUrl} is not a valid JSON object. Received type: ${typeof jsonObject}`);
|
|
@@ -105,7 +105,7 @@ export async function generateTypes() {
|
|
|
105
105
|
}
|
|
106
106
|
// Generate TypeScript interfaces using json-to-ts
|
|
107
107
|
const rootTypeName = 'ContentRoot'; // As per your previous update
|
|
108
|
-
console.log(chalk.
|
|
108
|
+
console.log(chalk.blue(`Generating TypeScript types with root name '${rootTypeName}'...`));
|
|
109
109
|
const typeDeclarations = jsonToTS.default(jsonObject, {
|
|
110
110
|
rootName: rootTypeName,
|
|
111
111
|
});
|
|
@@ -123,10 +123,6 @@ export async function generateTypes() {
|
|
|
123
123
|
catch (error) {
|
|
124
124
|
console.error(chalk.red.bold('\nError generating TypeScript types:'));
|
|
125
125
|
console.error(chalk.red(error.message));
|
|
126
|
-
// Optionally log stack for more details during development
|
|
127
|
-
// if (error.stack && process.env.NODE_ENV === 'development') {
|
|
128
|
-
// console.error(chalk.gray(error.stack));
|
|
129
|
-
// }
|
|
130
126
|
process.exit(1);
|
|
131
127
|
}
|
|
132
128
|
}
|
|
@@ -4,12 +4,13 @@ import fs from 'fs/promises';
|
|
|
4
4
|
import path from 'path';
|
|
5
5
|
import chalk from 'chalk';
|
|
6
6
|
import { loadConfig } from '../lib/configLoader.js';
|
|
7
|
+
import { CONTENTSTORAGE_CONFIG } from '../contentstorage-config.js';
|
|
7
8
|
export async function pullContent() {
|
|
8
9
|
console.log(chalk.blue('Starting content pull...'));
|
|
9
10
|
// Load configuration (assuming this function is defined elsewhere and works)
|
|
10
11
|
const config = await loadConfig();
|
|
11
|
-
console.log(chalk.
|
|
12
|
-
console.log(chalk.
|
|
12
|
+
console.log(chalk.blue(`Content key: ${config.contentKey}`));
|
|
13
|
+
console.log(chalk.blue(`Saving content to: ${config.contentDir}`));
|
|
13
14
|
try {
|
|
14
15
|
// Validate languageCodes array
|
|
15
16
|
if (!Array.isArray(config.languageCodes)) {
|
|
@@ -24,11 +25,11 @@ export async function pullContent() {
|
|
|
24
25
|
await fs.mkdir(config.contentDir, { recursive: true });
|
|
25
26
|
// Process each language code
|
|
26
27
|
for (const languageCode of config.languageCodes) {
|
|
27
|
-
const fileUrl = `${config.
|
|
28
|
+
const fileUrl = `${CONTENTSTORAGE_CONFIG.BASE_URL}/${config.contentKey}/content/${languageCode}.json`;
|
|
28
29
|
const filename = `${languageCode}.json`;
|
|
29
30
|
const outputPath = path.join(config.contentDir, filename);
|
|
30
31
|
console.log(chalk.blue(`\nProcessing language: ${languageCode}`));
|
|
31
|
-
console.log(chalk.
|
|
32
|
+
console.log(chalk.blue(`Using following contentKey to fetch json: ${config.contentKey}`));
|
|
32
33
|
try {
|
|
33
34
|
// Fetch data for the current language
|
|
34
35
|
const response = await axios.get(fileUrl);
|
package/dist/types.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export type AppConfig = {
|
|
2
2
|
languageCodes: LanguageCode[];
|
|
3
|
-
|
|
3
|
+
contentKey: string;
|
|
4
4
|
contentDir: string;
|
|
5
5
|
typesOutputFile: string;
|
|
6
6
|
};
|
|
@@ -23,7 +23,7 @@ export type LanguageCode = 'SQ' | 'BE' | 'BS' | 'BG' | 'HR' | 'CS' | 'DA' | 'NL'
|
|
|
23
23
|
export interface ContentStructure {
|
|
24
24
|
}
|
|
25
25
|
export interface ImageObject {
|
|
26
|
-
contentstorage_type:
|
|
26
|
+
contentstorage_type: 'image';
|
|
27
27
|
url: string;
|
|
28
28
|
altText: string;
|
|
29
29
|
}
|
|
@@ -31,6 +31,6 @@ export interface VariationData {
|
|
|
31
31
|
[key: string]: string;
|
|
32
32
|
}
|
|
33
33
|
export interface VariationObject {
|
|
34
|
-
contentstorage_type:
|
|
34
|
+
contentstorage_type: 'variation';
|
|
35
35
|
data: VariationData;
|
|
36
36
|
}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@contentstorage/core",
|
|
3
3
|
"author": "Kaido Hussar <kaidohus@gmail.com>",
|
|
4
4
|
"homepage": "https://contentstorage.app",
|
|
5
|
-
"version": "0.3.
|
|
5
|
+
"version": "0.3.30",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"description": "Fetch content from contentstorage and generate TypeScript types",
|
|
8
8
|
"module": "dist/index.js",
|