@intlify/unplugin-vue-i18n 11.0.1 → 11.0.7
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 +0 -2
- package/lib/index.cjs +29 -19
- package/lib/index.mjs +29 -19
- package/lib/vite.cjs +0 -1
- package/lib/vite.mjs +0 -1
- package/lib/webpack.cjs +0 -1
- package/lib/webpack.mjs +0 -1
- package/package.json +10 -10
package/README.md
CHANGED
|
@@ -311,12 +311,10 @@ If you need to use programmatically dynamic resource construction, you would be
|
|
|
311
311
|
Bundle target vue-i18n module. You can specify either `‘vue-i18n’` or `‘petite-vue-i18n’`.
|
|
312
312
|
|
|
313
313
|
The default is `'vue-i18n'`, and the following installed in node_modules will be bundled.
|
|
314
|
-
|
|
315
314
|
- development: `vue-i18n.esm-bundler.js`
|
|
316
315
|
- production: `vue-i18n.runtime.esm-bundler.js`
|
|
317
316
|
|
|
318
317
|
In the case of `‘petite-vue-i18n’`, the following installed in node_modules will be bundled.
|
|
319
|
-
|
|
320
318
|
- development: `petite-vue-i18n.esm-bundler.js`
|
|
321
319
|
- production: `petite-vue-i18n.runtime.esm-bundler.js`
|
|
322
320
|
|
package/lib/index.cjs
CHANGED
|
@@ -16,7 +16,6 @@ const pc = require('picocolors');
|
|
|
16
16
|
const eslintUitls = require('@eslint-community/eslint-utils');
|
|
17
17
|
const vueI18nExtensions = require('@intlify/vue-i18n-extensions');
|
|
18
18
|
const scopeManager = require('@typescript-eslint/scope-manager');
|
|
19
|
-
const typescriptEstree = require('@typescript-eslint/typescript-estree');
|
|
20
19
|
|
|
21
20
|
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
|
|
22
21
|
|
|
@@ -51,7 +50,7 @@ function resolveOptions(options) {
|
|
|
51
50
|
const translationIdentifiers = /* @__PURE__ */ new Map();
|
|
52
51
|
const transformI18nBlock = typeof options.transformI18nBlock === "function" ? options.transformI18nBlock : null;
|
|
53
52
|
return {
|
|
54
|
-
include: normalizeGlobOption(options.include),
|
|
53
|
+
include: normalizeGlobOption(options.include || []),
|
|
55
54
|
exclude: normalizeGlobOption(options.exclude),
|
|
56
55
|
module: moduleType,
|
|
57
56
|
onlyLocales,
|
|
@@ -689,6 +688,11 @@ async function getRaw(path) {
|
|
|
689
688
|
}
|
|
690
689
|
|
|
691
690
|
const debug$1 = createDebug__default(resolveNamespace("directive"));
|
|
691
|
+
const tsEstree = {
|
|
692
|
+
parse: void 0,
|
|
693
|
+
simpleTraverse: void 0,
|
|
694
|
+
AST_NODE_TYPES: void 0
|
|
695
|
+
};
|
|
692
696
|
function directivePlugin({
|
|
693
697
|
optimizeTranslationDirective,
|
|
694
698
|
translationIdentifiers
|
|
@@ -700,7 +704,13 @@ function directivePlugin({
|
|
|
700
704
|
name: resolveNamespace("directive"),
|
|
701
705
|
enforce: "pre",
|
|
702
706
|
vite: {
|
|
703
|
-
config(config) {
|
|
707
|
+
async config(config) {
|
|
708
|
+
await import('@typescript-eslint/typescript-estree').then((r) => {
|
|
709
|
+
tsEstree.parse = r.parse;
|
|
710
|
+
tsEstree.simpleTraverse = r.simpleTraverse;
|
|
711
|
+
tsEstree.AST_NODE_TYPES = r.AST_NODE_TYPES;
|
|
712
|
+
return;
|
|
713
|
+
});
|
|
704
714
|
vuePlugin = getVitePlugin(config, "vite:vue");
|
|
705
715
|
if (!checkVuePlugin(vuePlugin)) {
|
|
706
716
|
return;
|
|
@@ -776,8 +786,8 @@ function analyzeIdentifiers(descriptor, { root }, translationIdentifiers) {
|
|
|
776
786
|
if (!source) {
|
|
777
787
|
return;
|
|
778
788
|
}
|
|
779
|
-
const ast =
|
|
780
|
-
|
|
789
|
+
const ast = tsEstree.parse(source, { range: true });
|
|
790
|
+
tsEstree.simpleTraverse(ast, {
|
|
781
791
|
enter(node, parent) {
|
|
782
792
|
if (parent) {
|
|
783
793
|
node.parent = parent;
|
|
@@ -857,18 +867,18 @@ function getCallExpressionAndReturnStatement(scope, local) {
|
|
|
857
867
|
return EMPTY_NODE_RETURN;
|
|
858
868
|
}
|
|
859
869
|
const callExpressionRef = variable.references.find((ref) => {
|
|
860
|
-
return ref.identifier.parent?.type ===
|
|
870
|
+
return ref.identifier.parent?.type === tsEstree.AST_NODE_TYPES.CallExpression;
|
|
861
871
|
});
|
|
862
872
|
if (callExpressionRef == null) {
|
|
863
873
|
return EMPTY_NODE_RETURN;
|
|
864
874
|
}
|
|
865
875
|
let returnStatement = null;
|
|
866
|
-
if (callExpressionRef.from.type === "function" && callExpressionRef.from.block.type ===
|
|
867
|
-
callExpressionRef.from.block.parent.type ===
|
|
868
|
-
callExpressionRef.from.block.parent.key.type ===
|
|
876
|
+
if (callExpressionRef.from.type === "function" && callExpressionRef.from.block.type === tsEstree.AST_NODE_TYPES.FunctionExpression && // @ts-expect-error -- FIXME: type error
|
|
877
|
+
callExpressionRef.from.block.parent.type === tsEstree.AST_NODE_TYPES.Property && // @ts-expect-error -- FIXME: type error
|
|
878
|
+
callExpressionRef.from.block.parent.key.type === tsEstree.AST_NODE_TYPES.Identifier && // @ts-expect-error -- FIXME: type error
|
|
869
879
|
callExpressionRef.from.block.parent.key.name === "setup") {
|
|
870
880
|
returnStatement = callExpressionRef.from.block.body.body.find((statement) => {
|
|
871
|
-
return statement.type ===
|
|
881
|
+
return statement.type === tsEstree.AST_NODE_TYPES.ReturnStatement;
|
|
872
882
|
});
|
|
873
883
|
}
|
|
874
884
|
return {
|
|
@@ -878,22 +888,22 @@ function getCallExpressionAndReturnStatement(scope, local) {
|
|
|
878
888
|
};
|
|
879
889
|
}
|
|
880
890
|
function getVariableDeclarationIdFrom(node) {
|
|
881
|
-
if (node.parent?.type !==
|
|
891
|
+
if (node.parent?.type !== tsEstree.AST_NODE_TYPES.VariableDeclarator) {
|
|
882
892
|
return null;
|
|
883
893
|
}
|
|
884
894
|
return node.parent.id;
|
|
885
895
|
}
|
|
886
896
|
function parseVariableId(node) {
|
|
887
|
-
if (node.type ===
|
|
897
|
+
if (node.type === tsEstree.AST_NODE_TYPES.Identifier) {
|
|
888
898
|
return [{ key: node.name, value: null }];
|
|
889
899
|
} else {
|
|
890
900
|
const props = node.properties.filter(
|
|
891
901
|
// ignore RestElement
|
|
892
|
-
(prop) => prop.type ===
|
|
902
|
+
(prop) => prop.type === tsEstree.AST_NODE_TYPES.Property
|
|
893
903
|
);
|
|
894
904
|
const pairs = [];
|
|
895
905
|
for (const prop of props) {
|
|
896
|
-
if (prop?.key.type ===
|
|
906
|
+
if (prop?.key.type === tsEstree.AST_NODE_TYPES.Identifier && prop?.value.type === tsEstree.AST_NODE_TYPES.Identifier) {
|
|
897
907
|
pairs.push({ key: prop.key.name, value: prop.value.name });
|
|
898
908
|
}
|
|
899
909
|
}
|
|
@@ -905,12 +915,12 @@ function parseReturnStatement(node) {
|
|
|
905
915
|
if (node == null || node.argument == null) {
|
|
906
916
|
return pairs;
|
|
907
917
|
}
|
|
908
|
-
if (node.argument.type ===
|
|
918
|
+
if (node.argument.type === tsEstree.AST_NODE_TYPES.ObjectExpression) {
|
|
909
919
|
for (const prop of node.argument.properties) {
|
|
910
|
-
if (prop.type ===
|
|
911
|
-
if (prop.key.type ===
|
|
920
|
+
if (prop.type === tsEstree.AST_NODE_TYPES.Property) {
|
|
921
|
+
if (prop.key.type === tsEstree.AST_NODE_TYPES.Identifier && prop.value.type === tsEstree.AST_NODE_TYPES.Identifier) {
|
|
912
922
|
pairs.push({ key: prop.key.name, value: prop.value.name });
|
|
913
|
-
} else if (prop.key.type ===
|
|
923
|
+
} else if (prop.key.type === tsEstree.AST_NODE_TYPES.Identifier && prop.value.type === tsEstree.AST_NODE_TYPES.MemberExpression && prop.value.object.type === tsEstree.AST_NODE_TYPES.Identifier && prop.value.property.type === tsEstree.AST_NODE_TYPES.Identifier) {
|
|
914
924
|
pairs.push({
|
|
915
925
|
key: prop.key.name,
|
|
916
926
|
value: `${prop.value.object.name}.${prop.value.property.name}`
|
|
@@ -919,7 +929,7 @@ function parseReturnStatement(node) {
|
|
|
919
929
|
}
|
|
920
930
|
}
|
|
921
931
|
return pairs;
|
|
922
|
-
} else if (node.argument.type ===
|
|
932
|
+
} else if (node.argument.type === tsEstree.AST_NODE_TYPES.Identifier) {
|
|
923
933
|
return pairs;
|
|
924
934
|
} else {
|
|
925
935
|
return pairs;
|
package/lib/index.mjs
CHANGED
|
@@ -12,7 +12,6 @@ import pc from 'picocolors';
|
|
|
12
12
|
import eslintUitls from '@eslint-community/eslint-utils';
|
|
13
13
|
import { transformVTDirective } from '@intlify/vue-i18n-extensions';
|
|
14
14
|
import { analyze } from '@typescript-eslint/scope-manager';
|
|
15
|
-
import { parse as parse$2, simpleTraverse, AST_NODE_TYPES } from '@typescript-eslint/typescript-estree';
|
|
16
15
|
|
|
17
16
|
function normalizeGlobOption(val) {
|
|
18
17
|
if (!val) return void 0;
|
|
@@ -39,7 +38,7 @@ function resolveOptions(options) {
|
|
|
39
38
|
const translationIdentifiers = /* @__PURE__ */ new Map();
|
|
40
39
|
const transformI18nBlock = typeof options.transformI18nBlock === "function" ? options.transformI18nBlock : null;
|
|
41
40
|
return {
|
|
42
|
-
include: normalizeGlobOption(options.include),
|
|
41
|
+
include: normalizeGlobOption(options.include || []),
|
|
43
42
|
exclude: normalizeGlobOption(options.exclude),
|
|
44
43
|
module: moduleType,
|
|
45
44
|
onlyLocales,
|
|
@@ -677,6 +676,11 @@ async function getRaw(path) {
|
|
|
677
676
|
}
|
|
678
677
|
|
|
679
678
|
const debug$1 = createDebug(resolveNamespace("directive"));
|
|
679
|
+
const tsEstree = {
|
|
680
|
+
parse: void 0,
|
|
681
|
+
simpleTraverse: void 0,
|
|
682
|
+
AST_NODE_TYPES: void 0
|
|
683
|
+
};
|
|
680
684
|
function directivePlugin({
|
|
681
685
|
optimizeTranslationDirective,
|
|
682
686
|
translationIdentifiers
|
|
@@ -688,7 +692,13 @@ function directivePlugin({
|
|
|
688
692
|
name: resolveNamespace("directive"),
|
|
689
693
|
enforce: "pre",
|
|
690
694
|
vite: {
|
|
691
|
-
config(config) {
|
|
695
|
+
async config(config) {
|
|
696
|
+
await import('@typescript-eslint/typescript-estree').then((r) => {
|
|
697
|
+
tsEstree.parse = r.parse;
|
|
698
|
+
tsEstree.simpleTraverse = r.simpleTraverse;
|
|
699
|
+
tsEstree.AST_NODE_TYPES = r.AST_NODE_TYPES;
|
|
700
|
+
return;
|
|
701
|
+
});
|
|
692
702
|
vuePlugin = getVitePlugin(config, "vite:vue");
|
|
693
703
|
if (!checkVuePlugin(vuePlugin)) {
|
|
694
704
|
return;
|
|
@@ -764,8 +774,8 @@ function analyzeIdentifiers(descriptor, { root }, translationIdentifiers) {
|
|
|
764
774
|
if (!source) {
|
|
765
775
|
return;
|
|
766
776
|
}
|
|
767
|
-
const ast = parse
|
|
768
|
-
simpleTraverse(ast, {
|
|
777
|
+
const ast = tsEstree.parse(source, { range: true });
|
|
778
|
+
tsEstree.simpleTraverse(ast, {
|
|
769
779
|
enter(node, parent) {
|
|
770
780
|
if (parent) {
|
|
771
781
|
node.parent = parent;
|
|
@@ -845,18 +855,18 @@ function getCallExpressionAndReturnStatement(scope, local) {
|
|
|
845
855
|
return EMPTY_NODE_RETURN;
|
|
846
856
|
}
|
|
847
857
|
const callExpressionRef = variable.references.find((ref) => {
|
|
848
|
-
return ref.identifier.parent?.type === AST_NODE_TYPES.CallExpression;
|
|
858
|
+
return ref.identifier.parent?.type === tsEstree.AST_NODE_TYPES.CallExpression;
|
|
849
859
|
});
|
|
850
860
|
if (callExpressionRef == null) {
|
|
851
861
|
return EMPTY_NODE_RETURN;
|
|
852
862
|
}
|
|
853
863
|
let returnStatement = null;
|
|
854
|
-
if (callExpressionRef.from.type === "function" && callExpressionRef.from.block.type === AST_NODE_TYPES.FunctionExpression && // @ts-expect-error -- FIXME: type error
|
|
855
|
-
callExpressionRef.from.block.parent.type === AST_NODE_TYPES.Property && // @ts-expect-error -- FIXME: type error
|
|
856
|
-
callExpressionRef.from.block.parent.key.type === AST_NODE_TYPES.Identifier && // @ts-expect-error -- FIXME: type error
|
|
864
|
+
if (callExpressionRef.from.type === "function" && callExpressionRef.from.block.type === tsEstree.AST_NODE_TYPES.FunctionExpression && // @ts-expect-error -- FIXME: type error
|
|
865
|
+
callExpressionRef.from.block.parent.type === tsEstree.AST_NODE_TYPES.Property && // @ts-expect-error -- FIXME: type error
|
|
866
|
+
callExpressionRef.from.block.parent.key.type === tsEstree.AST_NODE_TYPES.Identifier && // @ts-expect-error -- FIXME: type error
|
|
857
867
|
callExpressionRef.from.block.parent.key.name === "setup") {
|
|
858
868
|
returnStatement = callExpressionRef.from.block.body.body.find((statement) => {
|
|
859
|
-
return statement.type === AST_NODE_TYPES.ReturnStatement;
|
|
869
|
+
return statement.type === tsEstree.AST_NODE_TYPES.ReturnStatement;
|
|
860
870
|
});
|
|
861
871
|
}
|
|
862
872
|
return {
|
|
@@ -866,22 +876,22 @@ function getCallExpressionAndReturnStatement(scope, local) {
|
|
|
866
876
|
};
|
|
867
877
|
}
|
|
868
878
|
function getVariableDeclarationIdFrom(node) {
|
|
869
|
-
if (node.parent?.type !== AST_NODE_TYPES.VariableDeclarator) {
|
|
879
|
+
if (node.parent?.type !== tsEstree.AST_NODE_TYPES.VariableDeclarator) {
|
|
870
880
|
return null;
|
|
871
881
|
}
|
|
872
882
|
return node.parent.id;
|
|
873
883
|
}
|
|
874
884
|
function parseVariableId(node) {
|
|
875
|
-
if (node.type === AST_NODE_TYPES.Identifier) {
|
|
885
|
+
if (node.type === tsEstree.AST_NODE_TYPES.Identifier) {
|
|
876
886
|
return [{ key: node.name, value: null }];
|
|
877
887
|
} else {
|
|
878
888
|
const props = node.properties.filter(
|
|
879
889
|
// ignore RestElement
|
|
880
|
-
(prop) => prop.type === AST_NODE_TYPES.Property
|
|
890
|
+
(prop) => prop.type === tsEstree.AST_NODE_TYPES.Property
|
|
881
891
|
);
|
|
882
892
|
const pairs = [];
|
|
883
893
|
for (const prop of props) {
|
|
884
|
-
if (prop?.key.type === AST_NODE_TYPES.Identifier && prop?.value.type === AST_NODE_TYPES.Identifier) {
|
|
894
|
+
if (prop?.key.type === tsEstree.AST_NODE_TYPES.Identifier && prop?.value.type === tsEstree.AST_NODE_TYPES.Identifier) {
|
|
885
895
|
pairs.push({ key: prop.key.name, value: prop.value.name });
|
|
886
896
|
}
|
|
887
897
|
}
|
|
@@ -893,12 +903,12 @@ function parseReturnStatement(node) {
|
|
|
893
903
|
if (node == null || node.argument == null) {
|
|
894
904
|
return pairs;
|
|
895
905
|
}
|
|
896
|
-
if (node.argument.type === AST_NODE_TYPES.ObjectExpression) {
|
|
906
|
+
if (node.argument.type === tsEstree.AST_NODE_TYPES.ObjectExpression) {
|
|
897
907
|
for (const prop of node.argument.properties) {
|
|
898
|
-
if (prop.type === AST_NODE_TYPES.Property) {
|
|
899
|
-
if (prop.key.type === AST_NODE_TYPES.Identifier && prop.value.type === AST_NODE_TYPES.Identifier) {
|
|
908
|
+
if (prop.type === tsEstree.AST_NODE_TYPES.Property) {
|
|
909
|
+
if (prop.key.type === tsEstree.AST_NODE_TYPES.Identifier && prop.value.type === tsEstree.AST_NODE_TYPES.Identifier) {
|
|
900
910
|
pairs.push({ key: prop.key.name, value: prop.value.name });
|
|
901
|
-
} else if (prop.key.type === AST_NODE_TYPES.Identifier && prop.value.type === AST_NODE_TYPES.MemberExpression && prop.value.object.type === AST_NODE_TYPES.Identifier && prop.value.property.type === AST_NODE_TYPES.Identifier) {
|
|
911
|
+
} else if (prop.key.type === tsEstree.AST_NODE_TYPES.Identifier && prop.value.type === tsEstree.AST_NODE_TYPES.MemberExpression && prop.value.object.type === tsEstree.AST_NODE_TYPES.Identifier && prop.value.property.type === tsEstree.AST_NODE_TYPES.Identifier) {
|
|
902
912
|
pairs.push({
|
|
903
913
|
key: prop.key.name,
|
|
904
914
|
value: `${prop.value.object.name}.${prop.value.property.name}`
|
|
@@ -907,7 +917,7 @@ function parseReturnStatement(node) {
|
|
|
907
917
|
}
|
|
908
918
|
}
|
|
909
919
|
return pairs;
|
|
910
|
-
} else if (node.argument.type === AST_NODE_TYPES.Identifier) {
|
|
920
|
+
} else if (node.argument.type === tsEstree.AST_NODE_TYPES.Identifier) {
|
|
911
921
|
return pairs;
|
|
912
922
|
} else {
|
|
913
923
|
return pairs;
|
package/lib/vite.cjs
CHANGED
|
@@ -15,7 +15,6 @@ require('picocolors');
|
|
|
15
15
|
require('@eslint-community/eslint-utils');
|
|
16
16
|
require('@intlify/vue-i18n-extensions');
|
|
17
17
|
require('@typescript-eslint/scope-manager');
|
|
18
|
-
require('@typescript-eslint/typescript-estree');
|
|
19
18
|
|
|
20
19
|
const vite = unplugin.createVitePlugin(index.unpluginFactory);
|
|
21
20
|
|
package/lib/vite.mjs
CHANGED
package/lib/webpack.cjs
CHANGED
|
@@ -15,7 +15,6 @@ require('picocolors');
|
|
|
15
15
|
require('@eslint-community/eslint-utils');
|
|
16
16
|
require('@intlify/vue-i18n-extensions');
|
|
17
17
|
require('@typescript-eslint/scope-manager');
|
|
18
|
-
require('@typescript-eslint/typescript-estree');
|
|
19
18
|
|
|
20
19
|
const webpack = unplugin.createWebpackPlugin(index.unpluginFactory);
|
|
21
20
|
|
package/lib/webpack.mjs
CHANGED
|
@@ -13,7 +13,6 @@ import 'picocolors';
|
|
|
13
13
|
import '@eslint-community/eslint-utils';
|
|
14
14
|
import '@intlify/vue-i18n-extensions';
|
|
15
15
|
import '@typescript-eslint/scope-manager';
|
|
16
|
-
import '@typescript-eslint/typescript-estree';
|
|
17
16
|
|
|
18
17
|
const webpack = createWebpackPlugin(unpluginFactory);
|
|
19
18
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@intlify/unplugin-vue-i18n",
|
|
3
|
-
"version": "11.0.
|
|
3
|
+
"version": "11.0.7",
|
|
4
4
|
"description": "unplugin for Vue I18n",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "kazuya kawaguchi",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"@eslint-community/eslint-utils": "^4.4.0",
|
|
27
|
-
"@intlify/shared": "^11.1.
|
|
27
|
+
"@intlify/shared": "^11.1.12",
|
|
28
28
|
"@intlify/vue-i18n-extensions": "^8.0.0",
|
|
29
29
|
"@rollup/pluginutils": "^5.1.0",
|
|
30
30
|
"@typescript-eslint/scope-manager": "^8.13.0",
|
|
@@ -34,25 +34,25 @@
|
|
|
34
34
|
"fast-glob": "^3.2.12",
|
|
35
35
|
"picocolors": "^1.0.0",
|
|
36
36
|
"unplugin": "^2.3.4",
|
|
37
|
-
"vue": "^3.5.
|
|
38
|
-
"@intlify/bundle-utils": "11.0.
|
|
37
|
+
"vue": "^3.5.21",
|
|
38
|
+
"@intlify/bundle-utils": "11.0.7"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"@intlify/core-base": "next",
|
|
42
42
|
"@types/debug": "^4.1.5",
|
|
43
43
|
"@types/jsdom": "^16.2.5",
|
|
44
44
|
"@types/memory-fs": "^0.3.2",
|
|
45
|
-
"@types/node": "^22.
|
|
45
|
+
"@types/node": "^22.18.4",
|
|
46
46
|
"@vitejs/plugin-vue": "^5.2.4",
|
|
47
47
|
"jsdom": "^25.0.1",
|
|
48
48
|
"memory-fs": "^0.5.0",
|
|
49
|
-
"source-map-js": "^1.
|
|
50
|
-
"ts-loader": "^9.5.
|
|
51
|
-
"unbuild": "^3.
|
|
52
|
-
"vite": "^6.3.
|
|
49
|
+
"source-map-js": "^1.2.1",
|
|
50
|
+
"ts-loader": "^9.5.4",
|
|
51
|
+
"unbuild": "^3.6.1",
|
|
52
|
+
"vite": "^6.3.6",
|
|
53
53
|
"rollup-vite": "npm:vite@^6.3.5",
|
|
54
54
|
"vue-loader": "^17.4.2",
|
|
55
|
-
"webpack": "^5.
|
|
55
|
+
"webpack": "^5.101.3",
|
|
56
56
|
"webpack-merge": "^5.9.0"
|
|
57
57
|
},
|
|
58
58
|
"engines": {
|