@lang-tag/cli 0.10.1 → 0.11.0
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/algorithms/config-generation/index.d.ts +7 -0
- package/algorithms/config-generation/path-based-config-generator.d.ts +110 -0
- package/algorithms/import/index.d.ts +7 -0
- package/algorithms/index.cjs +159 -0
- package/algorithms/index.d.ts +7 -0
- package/algorithms/index.js +142 -0
- package/config.d.ts +1 -0
- package/index.cjs +18 -12
- package/index.js +18 -12
- package/package.json +7 -1
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Predefined algorithms for onConfigGeneration hook.
|
|
3
|
+
*
|
|
4
|
+
* These algorithms customize how translation tag configurations are generated
|
|
5
|
+
* during collection and regeneration.
|
|
6
|
+
*/
|
|
7
|
+
export { pathBasedConfigGenerator, type PathBasedConfigGeneratorOptions } from './path-based-config-generator.ts';
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { LangTagCLIConfigGenerationEvent } from '../../config.ts';
|
|
2
|
+
export interface PathBasedConfigGeneratorOptions {
|
|
3
|
+
/**
|
|
4
|
+
* Whether to include the filename (without extension) as part of the path segments.
|
|
5
|
+
* @default false
|
|
6
|
+
*/
|
|
7
|
+
includeFileName?: boolean;
|
|
8
|
+
/**
|
|
9
|
+
* Whether to completely remove folders wrapped in brackets () or [].
|
|
10
|
+
* If false, only the brackets are removed from folder names.
|
|
11
|
+
* @default true
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* - true: 'app/(admin)/users' -> 'app/users'
|
|
15
|
+
* - false: 'app/(admin)/users' -> 'app/admin/users'
|
|
16
|
+
*/
|
|
17
|
+
removeBracketedFolders?: boolean;
|
|
18
|
+
/**
|
|
19
|
+
* List of folder names to completely ignore globally.
|
|
20
|
+
* These will be removed from all paths regardless of their position.
|
|
21
|
+
* @default []
|
|
22
|
+
*
|
|
23
|
+
* @example ['src', 'app', 'components']
|
|
24
|
+
*/
|
|
25
|
+
ignoreFolders?: string[];
|
|
26
|
+
/**
|
|
27
|
+
* When true, automatically extracts root folder names from the config.includes patterns
|
|
28
|
+
* and adds them to the ignoreFolders list.
|
|
29
|
+
*
|
|
30
|
+
* @default false
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* // With includes: ['src/**\/*.{js,ts,jsx,tsx}']
|
|
34
|
+
* // Automatically ignores: ['src']
|
|
35
|
+
*
|
|
36
|
+
* // With includes: ['(src|app)/**\/*.{js,ts,jsx,tsx}', 'components/**\/*.{jsx,tsx}']
|
|
37
|
+
* // Automatically ignores: ['src', 'app', 'components']
|
|
38
|
+
*/
|
|
39
|
+
ignoreIncludesRootFolders?: boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Hierarchical structure for ignoring specific folder patterns.
|
|
42
|
+
* Keys represent path segments to match, values indicate what to ignore at that level.
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* {
|
|
46
|
+
* 'src': {
|
|
47
|
+
* 'app': true, // ignore 'app' when under 'src'
|
|
48
|
+
* 'features': ['auth', 'admin'] // ignore 'auth' and 'admin' under 'src/features'
|
|
49
|
+
* }
|
|
50
|
+
* }
|
|
51
|
+
*/
|
|
52
|
+
ignoreStructured?: Record<string, any>;
|
|
53
|
+
/**
|
|
54
|
+
* Convert the final namespace to lowercase.
|
|
55
|
+
* @default false
|
|
56
|
+
*/
|
|
57
|
+
lowercaseNamespace?: boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Case transformation to apply to the namespace.
|
|
60
|
+
* Available options: 'camel', 'capital', 'constant', 'dot', 'header', 'kebab',
|
|
61
|
+
* 'lower', 'no', 'param', 'pascal', 'path', 'sentence', 'snake', 'swap', 'title', 'upper'
|
|
62
|
+
* @default undefined (no transformation)
|
|
63
|
+
*/
|
|
64
|
+
namespaceCase?: 'camel' | 'capital' | 'constant' | 'dot' | 'header' | 'kebab' | 'lower' | 'no' | 'param' | 'pascal' | 'path' | 'sentence' | 'snake' | 'swap' | 'title' | 'upper';
|
|
65
|
+
/**
|
|
66
|
+
* Case transformation to apply to the path segments.
|
|
67
|
+
* Available options: 'camel', 'capital', 'constant', 'dot', 'header', 'kebab',
|
|
68
|
+
* 'lower', 'no', 'param', 'pascal', 'path', 'sentence', 'snake', 'swap', 'title', 'upper'
|
|
69
|
+
* @default undefined (no transformation)
|
|
70
|
+
*/
|
|
71
|
+
pathCase?: 'camel' | 'capital' | 'constant' | 'dot' | 'header' | 'kebab' | 'lower' | 'no' | 'param' | 'pascal' | 'path' | 'sentence' | 'snake' | 'swap' | 'title' | 'upper';
|
|
72
|
+
/**
|
|
73
|
+
* Fallback namespace to use when no segments remain after filtering.
|
|
74
|
+
* Defaults to the defaultNamespace from langTagConfig.collect.defaultNamespace if not provided.
|
|
75
|
+
* @default undefined
|
|
76
|
+
*/
|
|
77
|
+
fallbackNamespace?: string;
|
|
78
|
+
/**
|
|
79
|
+
* When true and the generated namespace equals the fallback/default namespace,
|
|
80
|
+
* the namespace will be omitted from the configuration as it's redundant.
|
|
81
|
+
* @default true
|
|
82
|
+
*/
|
|
83
|
+
clearOnDefaultNamespace?: boolean;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Automatically generates namespace and path configuration based on file path structure.
|
|
87
|
+
*
|
|
88
|
+
* This algorithm analyzes the relative file path and intelligently extracts namespace
|
|
89
|
+
* and path segments according to configurable rules.
|
|
90
|
+
*
|
|
91
|
+
* @param options - Configuration options for path-based generation
|
|
92
|
+
* @returns A function compatible with LangTagCLIConfig.onConfigGeneration
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* ```typescript
|
|
96
|
+
* import { pathBasedConfigGenerator } from '@lang-tag/cli/algorithms';
|
|
97
|
+
*
|
|
98
|
+
* export default {
|
|
99
|
+
* onConfigGeneration: pathBasedConfigGenerator({
|
|
100
|
+
* includeFileName: false,
|
|
101
|
+
* removeBracketedFolders: true,
|
|
102
|
+
* ignoreFolders: ['lib', 'utils'],
|
|
103
|
+
* ignoreIncludesRootFolders: true, // Auto-ignores root folders from includes
|
|
104
|
+
* lowercaseNamespace: true,
|
|
105
|
+
* fallbackNamespace: 'common'
|
|
106
|
+
* })
|
|
107
|
+
* };
|
|
108
|
+
* ```
|
|
109
|
+
*/
|
|
110
|
+
export declare function pathBasedConfigGenerator(options?: PathBasedConfigGeneratorOptions): (event: LangTagCLIConfigGenerationEvent) => Promise<void>;
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const path = require("pathe");
|
|
4
|
+
const caseLib = require("case");
|
|
5
|
+
function _interopNamespaceDefault(e) {
|
|
6
|
+
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
|
|
7
|
+
if (e) {
|
|
8
|
+
for (const k in e) {
|
|
9
|
+
if (k !== "default") {
|
|
10
|
+
const d = Object.getOwnPropertyDescriptor(e, k);
|
|
11
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
12
|
+
enumerable: true,
|
|
13
|
+
get: () => e[k]
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
n.default = e;
|
|
19
|
+
return Object.freeze(n);
|
|
20
|
+
}
|
|
21
|
+
const caseLib__namespace = /* @__PURE__ */ _interopNamespaceDefault(caseLib);
|
|
22
|
+
function pathBasedConfigGenerator(options = {}) {
|
|
23
|
+
const {
|
|
24
|
+
includeFileName = false,
|
|
25
|
+
removeBracketedFolders = true,
|
|
26
|
+
ignoreFolders = [],
|
|
27
|
+
ignoreIncludesRootFolders = false,
|
|
28
|
+
ignoreStructured = {},
|
|
29
|
+
lowercaseNamespace = false,
|
|
30
|
+
namespaceCase,
|
|
31
|
+
pathCase,
|
|
32
|
+
fallbackNamespace,
|
|
33
|
+
clearOnDefaultNamespace = true
|
|
34
|
+
} = options;
|
|
35
|
+
return async (event) => {
|
|
36
|
+
const { relativePath, langTagConfig } = event;
|
|
37
|
+
const actualFallbackNamespace = fallbackNamespace ?? langTagConfig.collect?.defaultNamespace;
|
|
38
|
+
let finalIgnoreFolders = [...ignoreFolders];
|
|
39
|
+
if (ignoreIncludesRootFolders && langTagConfig.includes) {
|
|
40
|
+
const extractedFolders = extractRootFoldersFromIncludes(langTagConfig.includes);
|
|
41
|
+
finalIgnoreFolders = [.../* @__PURE__ */ new Set([...finalIgnoreFolders, ...extractedFolders])];
|
|
42
|
+
}
|
|
43
|
+
let pathSegments = relativePath.split(path.sep).filter(Boolean);
|
|
44
|
+
if (pathSegments.length === 0) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const fileName = pathSegments[pathSegments.length - 1];
|
|
48
|
+
const fileNameWithoutExt = fileName.replace(/\.[^.]+$/, "");
|
|
49
|
+
if (includeFileName) {
|
|
50
|
+
pathSegments[pathSegments.length - 1] = fileNameWithoutExt;
|
|
51
|
+
} else {
|
|
52
|
+
pathSegments = pathSegments.slice(0, -1);
|
|
53
|
+
}
|
|
54
|
+
pathSegments = pathSegments.map((segment) => {
|
|
55
|
+
const bracketMatch = segment.match(/^[\(\[](.+)[\)\]]$/);
|
|
56
|
+
if (bracketMatch) {
|
|
57
|
+
return removeBracketedFolders ? null : bracketMatch[1];
|
|
58
|
+
}
|
|
59
|
+
return segment;
|
|
60
|
+
}).filter((seg) => seg !== null);
|
|
61
|
+
pathSegments = applyStructuredIgnore(pathSegments, ignoreStructured);
|
|
62
|
+
pathSegments = pathSegments.filter((seg) => !finalIgnoreFolders.includes(seg));
|
|
63
|
+
let namespace;
|
|
64
|
+
let path$1;
|
|
65
|
+
if (pathSegments.length >= 1) {
|
|
66
|
+
namespace = pathSegments[0];
|
|
67
|
+
if (pathSegments.length > 1) {
|
|
68
|
+
path$1 = pathSegments.slice(1).join(".");
|
|
69
|
+
}
|
|
70
|
+
} else {
|
|
71
|
+
namespace = actualFallbackNamespace;
|
|
72
|
+
}
|
|
73
|
+
if (namespace) {
|
|
74
|
+
if (lowercaseNamespace) {
|
|
75
|
+
namespace = namespace.toLowerCase();
|
|
76
|
+
}
|
|
77
|
+
if (namespaceCase) {
|
|
78
|
+
namespace = applyCaseTransform(namespace, namespaceCase);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
if (path$1 && pathCase) {
|
|
82
|
+
const pathParts = path$1.split(".");
|
|
83
|
+
const transformedParts = pathParts.map((part) => applyCaseTransform(part, pathCase));
|
|
84
|
+
path$1 = transformedParts.join(".");
|
|
85
|
+
}
|
|
86
|
+
const newConfig = {};
|
|
87
|
+
if (clearOnDefaultNamespace && namespace === actualFallbackNamespace) {
|
|
88
|
+
if (path$1) {
|
|
89
|
+
newConfig.path = path$1;
|
|
90
|
+
} else {
|
|
91
|
+
event.save(void 0);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
} else {
|
|
95
|
+
if (namespace) {
|
|
96
|
+
newConfig.namespace = namespace;
|
|
97
|
+
}
|
|
98
|
+
if (path$1) {
|
|
99
|
+
newConfig.path = path$1;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
if (Object.keys(newConfig).length > 0) {
|
|
103
|
+
event.save(newConfig);
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
function applyStructuredIgnore(segments, structure) {
|
|
108
|
+
const result = [];
|
|
109
|
+
let currentStructure = structure;
|
|
110
|
+
for (let i = 0; i < segments.length; i++) {
|
|
111
|
+
const segment = segments[i];
|
|
112
|
+
if (segment in currentStructure) {
|
|
113
|
+
const rule = currentStructure[segment];
|
|
114
|
+
if (rule === true) {
|
|
115
|
+
currentStructure = structure;
|
|
116
|
+
continue;
|
|
117
|
+
} else if (Array.isArray(rule)) {
|
|
118
|
+
result.push(segment);
|
|
119
|
+
if (i + 1 < segments.length && rule.includes(segments[i + 1])) {
|
|
120
|
+
i++;
|
|
121
|
+
}
|
|
122
|
+
currentStructure = structure;
|
|
123
|
+
continue;
|
|
124
|
+
} else if (typeof rule === "object" && rule !== null) {
|
|
125
|
+
result.push(segment);
|
|
126
|
+
currentStructure = rule;
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
result.push(segment);
|
|
131
|
+
currentStructure = structure;
|
|
132
|
+
}
|
|
133
|
+
return result;
|
|
134
|
+
}
|
|
135
|
+
function applyCaseTransform(str, caseType) {
|
|
136
|
+
const caseFunction = caseLib__namespace[caseType];
|
|
137
|
+
if (typeof caseFunction === "function") {
|
|
138
|
+
return caseFunction(str);
|
|
139
|
+
}
|
|
140
|
+
return str;
|
|
141
|
+
}
|
|
142
|
+
function extractRootFoldersFromIncludes(includes) {
|
|
143
|
+
const folders = /* @__PURE__ */ new Set();
|
|
144
|
+
for (const pattern of includes) {
|
|
145
|
+
let cleanPattern = pattern.replace(/^\.\//, "");
|
|
146
|
+
const match = cleanPattern.match(/^([^/]+)/);
|
|
147
|
+
if (!match) continue;
|
|
148
|
+
const firstSegment = match[1];
|
|
149
|
+
const groupMatch = firstSegment.match(/^[\(\[]([^\)\]]+)[\)\]]$/);
|
|
150
|
+
if (groupMatch) {
|
|
151
|
+
const groupFolders = groupMatch[1].split("|").map((f) => f.trim());
|
|
152
|
+
groupFolders.forEach((folder) => folders.add(folder));
|
|
153
|
+
} else {
|
|
154
|
+
folders.add(firstSegment);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return Array.from(folders);
|
|
158
|
+
}
|
|
159
|
+
exports.pathBasedConfigGenerator = pathBasedConfigGenerator;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Predefined algorithms for lang-tag-cli configuration.
|
|
3
|
+
*
|
|
4
|
+
* These algorithms can be used in your lang-tag-cli config file
|
|
5
|
+
* to customize how tags are processed during collection and regeneration.
|
|
6
|
+
*/
|
|
7
|
+
export { pathBasedConfigGenerator, type PathBasedConfigGeneratorOptions } from './config-generation/index.ts';
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { sep } from "pathe";
|
|
2
|
+
import * as caseLib from "case";
|
|
3
|
+
function pathBasedConfigGenerator(options = {}) {
|
|
4
|
+
const {
|
|
5
|
+
includeFileName = false,
|
|
6
|
+
removeBracketedFolders = true,
|
|
7
|
+
ignoreFolders = [],
|
|
8
|
+
ignoreIncludesRootFolders = false,
|
|
9
|
+
ignoreStructured = {},
|
|
10
|
+
lowercaseNamespace = false,
|
|
11
|
+
namespaceCase,
|
|
12
|
+
pathCase,
|
|
13
|
+
fallbackNamespace,
|
|
14
|
+
clearOnDefaultNamespace = true
|
|
15
|
+
} = options;
|
|
16
|
+
return async (event) => {
|
|
17
|
+
const { relativePath, langTagConfig } = event;
|
|
18
|
+
const actualFallbackNamespace = fallbackNamespace ?? langTagConfig.collect?.defaultNamespace;
|
|
19
|
+
let finalIgnoreFolders = [...ignoreFolders];
|
|
20
|
+
if (ignoreIncludesRootFolders && langTagConfig.includes) {
|
|
21
|
+
const extractedFolders = extractRootFoldersFromIncludes(langTagConfig.includes);
|
|
22
|
+
finalIgnoreFolders = [.../* @__PURE__ */ new Set([...finalIgnoreFolders, ...extractedFolders])];
|
|
23
|
+
}
|
|
24
|
+
let pathSegments = relativePath.split(sep).filter(Boolean);
|
|
25
|
+
if (pathSegments.length === 0) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const fileName = pathSegments[pathSegments.length - 1];
|
|
29
|
+
const fileNameWithoutExt = fileName.replace(/\.[^.]+$/, "");
|
|
30
|
+
if (includeFileName) {
|
|
31
|
+
pathSegments[pathSegments.length - 1] = fileNameWithoutExt;
|
|
32
|
+
} else {
|
|
33
|
+
pathSegments = pathSegments.slice(0, -1);
|
|
34
|
+
}
|
|
35
|
+
pathSegments = pathSegments.map((segment) => {
|
|
36
|
+
const bracketMatch = segment.match(/^[\(\[](.+)[\)\]]$/);
|
|
37
|
+
if (bracketMatch) {
|
|
38
|
+
return removeBracketedFolders ? null : bracketMatch[1];
|
|
39
|
+
}
|
|
40
|
+
return segment;
|
|
41
|
+
}).filter((seg) => seg !== null);
|
|
42
|
+
pathSegments = applyStructuredIgnore(pathSegments, ignoreStructured);
|
|
43
|
+
pathSegments = pathSegments.filter((seg) => !finalIgnoreFolders.includes(seg));
|
|
44
|
+
let namespace;
|
|
45
|
+
let path;
|
|
46
|
+
if (pathSegments.length >= 1) {
|
|
47
|
+
namespace = pathSegments[0];
|
|
48
|
+
if (pathSegments.length > 1) {
|
|
49
|
+
path = pathSegments.slice(1).join(".");
|
|
50
|
+
}
|
|
51
|
+
} else {
|
|
52
|
+
namespace = actualFallbackNamespace;
|
|
53
|
+
}
|
|
54
|
+
if (namespace) {
|
|
55
|
+
if (lowercaseNamespace) {
|
|
56
|
+
namespace = namespace.toLowerCase();
|
|
57
|
+
}
|
|
58
|
+
if (namespaceCase) {
|
|
59
|
+
namespace = applyCaseTransform(namespace, namespaceCase);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (path && pathCase) {
|
|
63
|
+
const pathParts = path.split(".");
|
|
64
|
+
const transformedParts = pathParts.map((part) => applyCaseTransform(part, pathCase));
|
|
65
|
+
path = transformedParts.join(".");
|
|
66
|
+
}
|
|
67
|
+
const newConfig = {};
|
|
68
|
+
if (clearOnDefaultNamespace && namespace === actualFallbackNamespace) {
|
|
69
|
+
if (path) {
|
|
70
|
+
newConfig.path = path;
|
|
71
|
+
} else {
|
|
72
|
+
event.save(void 0);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
} else {
|
|
76
|
+
if (namespace) {
|
|
77
|
+
newConfig.namespace = namespace;
|
|
78
|
+
}
|
|
79
|
+
if (path) {
|
|
80
|
+
newConfig.path = path;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
if (Object.keys(newConfig).length > 0) {
|
|
84
|
+
event.save(newConfig);
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
function applyStructuredIgnore(segments, structure) {
|
|
89
|
+
const result = [];
|
|
90
|
+
let currentStructure = structure;
|
|
91
|
+
for (let i = 0; i < segments.length; i++) {
|
|
92
|
+
const segment = segments[i];
|
|
93
|
+
if (segment in currentStructure) {
|
|
94
|
+
const rule = currentStructure[segment];
|
|
95
|
+
if (rule === true) {
|
|
96
|
+
currentStructure = structure;
|
|
97
|
+
continue;
|
|
98
|
+
} else if (Array.isArray(rule)) {
|
|
99
|
+
result.push(segment);
|
|
100
|
+
if (i + 1 < segments.length && rule.includes(segments[i + 1])) {
|
|
101
|
+
i++;
|
|
102
|
+
}
|
|
103
|
+
currentStructure = structure;
|
|
104
|
+
continue;
|
|
105
|
+
} else if (typeof rule === "object" && rule !== null) {
|
|
106
|
+
result.push(segment);
|
|
107
|
+
currentStructure = rule;
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
result.push(segment);
|
|
112
|
+
currentStructure = structure;
|
|
113
|
+
}
|
|
114
|
+
return result;
|
|
115
|
+
}
|
|
116
|
+
function applyCaseTransform(str, caseType) {
|
|
117
|
+
const caseFunction = caseLib[caseType];
|
|
118
|
+
if (typeof caseFunction === "function") {
|
|
119
|
+
return caseFunction(str);
|
|
120
|
+
}
|
|
121
|
+
return str;
|
|
122
|
+
}
|
|
123
|
+
function extractRootFoldersFromIncludes(includes) {
|
|
124
|
+
const folders = /* @__PURE__ */ new Set();
|
|
125
|
+
for (const pattern of includes) {
|
|
126
|
+
let cleanPattern = pattern.replace(/^\.\//, "");
|
|
127
|
+
const match = cleanPattern.match(/^([^/]+)/);
|
|
128
|
+
if (!match) continue;
|
|
129
|
+
const firstSegment = match[1];
|
|
130
|
+
const groupMatch = firstSegment.match(/^[\(\[]([^\)\]]+)[\)\]]$/);
|
|
131
|
+
if (groupMatch) {
|
|
132
|
+
const groupFolders = groupMatch[1].split("|").map((f) => f.trim());
|
|
133
|
+
groupFolders.forEach((folder) => folders.add(folder));
|
|
134
|
+
} else {
|
|
135
|
+
folders.add(firstSegment);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return Array.from(folders);
|
|
139
|
+
}
|
|
140
|
+
export {
|
|
141
|
+
pathBasedConfigGenerator
|
|
142
|
+
};
|
package/config.d.ts
CHANGED
|
@@ -170,6 +170,7 @@ export interface LangTagCLIConfigGenerationEvent {
|
|
|
170
170
|
isImportedLibrary: boolean;
|
|
171
171
|
/** The configuration object extracted from the lang tag's options argument (e.g., `{ namespace: 'common', path: 'my.path' }`). */
|
|
172
172
|
config: LangTagTranslationsConfig | undefined;
|
|
173
|
+
langTagConfig: LangTagCLIConfig;
|
|
173
174
|
/**
|
|
174
175
|
* Tells CLI to replace tag configuration
|
|
175
176
|
* undefined = means configuration will be removed
|
package/index.cjs
CHANGED
|
@@ -441,6 +441,7 @@ async function checkAndRegenerateFileLangTags(config, logger, file, path$12) {
|
|
|
441
441
|
let newConfig = void 0;
|
|
442
442
|
let shouldUpdate = false;
|
|
443
443
|
await config.onConfigGeneration({
|
|
444
|
+
langTagConfig: config,
|
|
444
445
|
config: tag.parameterConfig,
|
|
445
446
|
absolutePath: file,
|
|
446
447
|
relativePath: path$12,
|
|
@@ -1414,13 +1415,22 @@ async function detectModuleSystem() {
|
|
|
1414
1415
|
return "cjs";
|
|
1415
1416
|
}
|
|
1416
1417
|
}
|
|
1417
|
-
function getExportStatement(moduleSystem) {
|
|
1418
|
-
return moduleSystem === "esm" ? "export default config;" : "module.exports = config;";
|
|
1419
|
-
}
|
|
1420
1418
|
async function generateDefaultConfig() {
|
|
1421
1419
|
const moduleSystem = await detectModuleSystem();
|
|
1422
|
-
const
|
|
1423
|
-
|
|
1420
|
+
const importStatement = moduleSystem === "esm" ? `import { pathBasedConfigGenerator } from '@lang-tag/cli/algorithms';` : `const { pathBasedConfigGenerator } = require('@lang-tag/cli/algorithms');`;
|
|
1421
|
+
const exportStatement = moduleSystem === "esm" ? "export default config;" : "module.exports = config;";
|
|
1422
|
+
return `${importStatement}
|
|
1423
|
+
|
|
1424
|
+
const generationAlgorithm = pathBasedConfigGenerator({
|
|
1425
|
+
ignoreIncludesRootFolders: true,
|
|
1426
|
+
removeBracketedFolders: true,
|
|
1427
|
+
namespaceCase: 'kebab',
|
|
1428
|
+
pathCase: 'camel',
|
|
1429
|
+
clearOnDefaultNamespace: true,
|
|
1430
|
+
ignoreFolders: ['core', 'utils', 'helpers']
|
|
1431
|
+
});
|
|
1432
|
+
|
|
1433
|
+
/** @type {import('@lang-tag/cli/config').LangTagCLIConfig} */
|
|
1424
1434
|
const config = {
|
|
1425
1435
|
tagName: 'lang',
|
|
1426
1436
|
isLibrary: false,
|
|
@@ -1431,13 +1441,9 @@ const config = {
|
|
|
1431
1441
|
// We do not modify imported configurations
|
|
1432
1442
|
if (event.isImportedLibrary) return;
|
|
1433
1443
|
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
// config.path = 'test';
|
|
1438
|
-
// config.namespace = 'testNamespace';
|
|
1439
|
-
// event.save(config);
|
|
1440
|
-
// }
|
|
1444
|
+
if (event.config?.manual) return;
|
|
1445
|
+
|
|
1446
|
+
await generationAlgorithm(event);
|
|
1441
1447
|
},
|
|
1442
1448
|
collect: {
|
|
1443
1449
|
defaultNamespace: 'common',
|
package/index.js
CHANGED
|
@@ -421,6 +421,7 @@ async function checkAndRegenerateFileLangTags(config, logger, file, path2) {
|
|
|
421
421
|
let newConfig = void 0;
|
|
422
422
|
let shouldUpdate = false;
|
|
423
423
|
await config.onConfigGeneration({
|
|
424
|
+
langTagConfig: config,
|
|
424
425
|
config: tag.parameterConfig,
|
|
425
426
|
absolutePath: file,
|
|
426
427
|
relativePath: path2,
|
|
@@ -1394,13 +1395,22 @@ async function detectModuleSystem() {
|
|
|
1394
1395
|
return "cjs";
|
|
1395
1396
|
}
|
|
1396
1397
|
}
|
|
1397
|
-
function getExportStatement(moduleSystem) {
|
|
1398
|
-
return moduleSystem === "esm" ? "export default config;" : "module.exports = config;";
|
|
1399
|
-
}
|
|
1400
1398
|
async function generateDefaultConfig() {
|
|
1401
1399
|
const moduleSystem = await detectModuleSystem();
|
|
1402
|
-
const
|
|
1403
|
-
|
|
1400
|
+
const importStatement = moduleSystem === "esm" ? `import { pathBasedConfigGenerator } from '@lang-tag/cli/algorithms';` : `const { pathBasedConfigGenerator } = require('@lang-tag/cli/algorithms');`;
|
|
1401
|
+
const exportStatement = moduleSystem === "esm" ? "export default config;" : "module.exports = config;";
|
|
1402
|
+
return `${importStatement}
|
|
1403
|
+
|
|
1404
|
+
const generationAlgorithm = pathBasedConfigGenerator({
|
|
1405
|
+
ignoreIncludesRootFolders: true,
|
|
1406
|
+
removeBracketedFolders: true,
|
|
1407
|
+
namespaceCase: 'kebab',
|
|
1408
|
+
pathCase: 'camel',
|
|
1409
|
+
clearOnDefaultNamespace: true,
|
|
1410
|
+
ignoreFolders: ['core', 'utils', 'helpers']
|
|
1411
|
+
});
|
|
1412
|
+
|
|
1413
|
+
/** @type {import('@lang-tag/cli/config').LangTagCLIConfig} */
|
|
1404
1414
|
const config = {
|
|
1405
1415
|
tagName: 'lang',
|
|
1406
1416
|
isLibrary: false,
|
|
@@ -1411,13 +1421,9 @@ const config = {
|
|
|
1411
1421
|
// We do not modify imported configurations
|
|
1412
1422
|
if (event.isImportedLibrary) return;
|
|
1413
1423
|
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
// config.path = 'test';
|
|
1418
|
-
// config.namespace = 'testNamespace';
|
|
1419
|
-
// event.save(config);
|
|
1420
|
-
// }
|
|
1424
|
+
if (event.config?.manual) return;
|
|
1425
|
+
|
|
1426
|
+
await generationAlgorithm(event);
|
|
1421
1427
|
},
|
|
1422
1428
|
collect: {
|
|
1423
1429
|
defaultNamespace: 'common',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lang-tag/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -22,6 +22,11 @@
|
|
|
22
22
|
".": {
|
|
23
23
|
"import": "./index.js",
|
|
24
24
|
"require": "./index.cjs"
|
|
25
|
+
},
|
|
26
|
+
"./algorithms": {
|
|
27
|
+
"types": "./algorithms/index.d.ts",
|
|
28
|
+
"import": "./algorithms/index.js",
|
|
29
|
+
"require": "./algorithms/index.cjs"
|
|
25
30
|
}
|
|
26
31
|
},
|
|
27
32
|
"peerDependencies": {
|
|
@@ -29,6 +34,7 @@
|
|
|
29
34
|
},
|
|
30
35
|
"dependencies": {
|
|
31
36
|
"acorn": "^8.15.0",
|
|
37
|
+
"case": "^1.6.3",
|
|
32
38
|
"chokidar": "^4.0.3",
|
|
33
39
|
"commander": "^13.1.0",
|
|
34
40
|
"globby": "^14.1.0",
|