next-openapi-gen 0.6.5 → 0.6.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/dist/lib/logger.js
CHANGED
|
@@ -18,21 +18,21 @@ class Logger {
|
|
|
18
18
|
return 'Unknown';
|
|
19
19
|
}
|
|
20
20
|
log(message, ...args) {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
console.log(`[${source}] ${message}`, ...args);
|
|
24
|
-
}
|
|
21
|
+
const source = this.getCallerInfo();
|
|
22
|
+
console.log(`[${source}] ${message}`, ...args);
|
|
25
23
|
}
|
|
26
24
|
warn(message, ...args) {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
console.warn(`[${source}] ${message}`, ...args);
|
|
30
|
-
}
|
|
25
|
+
const source = this.getCallerInfo();
|
|
26
|
+
console.warn(`[${source}] ${message}`, ...args);
|
|
31
27
|
}
|
|
32
28
|
error(message, ...args) {
|
|
29
|
+
const source = this.getCallerInfo();
|
|
30
|
+
console.error(`[${source}] ${message}`, ...args);
|
|
31
|
+
}
|
|
32
|
+
debug(message, ...args) {
|
|
33
33
|
if (this.config?.debug) {
|
|
34
34
|
const source = this.getCallerInfo();
|
|
35
|
-
console.
|
|
35
|
+
console.log(`[${source}] ${message}`, ...args);
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
38
|
}
|
|
@@ -39,7 +39,7 @@ export class OpenApiGenerator {
|
|
|
39
39
|
let appRouterApiDir = "";
|
|
40
40
|
if (fs.existsSync(path.join(path.dirname(apiDir), "app", "api"))) {
|
|
41
41
|
appRouterApiDir = path.join(path.dirname(apiDir), "app", "api");
|
|
42
|
-
logger.
|
|
42
|
+
logger.debug(`Found app router API directory at ${appRouterApiDir}`);
|
|
43
43
|
}
|
|
44
44
|
// Scan pages router routes
|
|
45
45
|
this.routeProcessor.scanApiRoutes(apiDir);
|
|
@@ -137,7 +137,7 @@ export class RouteProcessor {
|
|
|
137
137
|
const pathParams = extractPathParameters(routePath);
|
|
138
138
|
// If we have path parameters but no pathParamsType defined, we should log a warning
|
|
139
139
|
if (pathParams.length > 0 && !dataTypes.pathParamsType) {
|
|
140
|
-
logger.
|
|
140
|
+
logger.debug(`Route ${routePath} contains path parameters ${pathParams.join(", ")} but no @pathParams type is defined.`);
|
|
141
141
|
}
|
|
142
142
|
this.addRouteToPaths(declaration.id.name, filePath, dataTypes);
|
|
143
143
|
}
|
|
@@ -154,7 +154,7 @@ export class RouteProcessor {
|
|
|
154
154
|
const routePath = this.getRoutePath(filePath);
|
|
155
155
|
const pathParams = extractPathParameters(routePath);
|
|
156
156
|
if (pathParams.length > 0 && !dataTypes.pathParamsType) {
|
|
157
|
-
logger.
|
|
157
|
+
logger.debug(`Route ${routePath} contains path parameters ${pathParams.join(", ")} but no @pathParams type is defined.`);
|
|
158
158
|
}
|
|
159
159
|
this.addRouteToPaths(decl.id.name, filePath, dataTypes);
|
|
160
160
|
}
|
|
@@ -167,7 +167,7 @@ export class RouteProcessor {
|
|
|
167
167
|
this.processFileTracker[filePath] = true;
|
|
168
168
|
}
|
|
169
169
|
scanApiRoutes(dir) {
|
|
170
|
-
logger.
|
|
170
|
+
logger.debug(`Scanning API routes in: ${dir}`);
|
|
171
171
|
let files = this.directoryCache[dir];
|
|
172
172
|
if (!files) {
|
|
173
173
|
files = fs.readdirSync(dir);
|
|
@@ -16,6 +16,7 @@ export class SchemaProcessor {
|
|
|
16
16
|
processingTypes = new Set();
|
|
17
17
|
zodSchemaConverter;
|
|
18
18
|
schemaType;
|
|
19
|
+
isResolvingPickOmitBase = false;
|
|
19
20
|
constructor(schemaDir, schemaType = "typescript") {
|
|
20
21
|
this.schemaDir = path.resolve(schemaDir);
|
|
21
22
|
this.schemaType = schemaType;
|
|
@@ -43,20 +44,20 @@ export class SchemaProcessor {
|
|
|
43
44
|
this.contentType = contentType;
|
|
44
45
|
// Check if we should use Zod schemas
|
|
45
46
|
if (this.schemaType === "zod") {
|
|
46
|
-
logger.
|
|
47
|
+
logger.debug(`Looking for Zod schema: ${schemaName}`);
|
|
47
48
|
// Check type mapping first
|
|
48
49
|
const mappedSchemaName = this.zodSchemaConverter.typeToSchemaMapping[schemaName];
|
|
49
50
|
if (mappedSchemaName) {
|
|
50
|
-
logger.
|
|
51
|
+
logger.debug(`Type '${schemaName}' is mapped to Zod schema '${mappedSchemaName}'`);
|
|
51
52
|
}
|
|
52
53
|
// Try to convert Zod schema
|
|
53
54
|
const zodSchema = this.zodSchemaConverter.convertZodSchemaToOpenApi(schemaName);
|
|
54
55
|
if (zodSchema) {
|
|
55
|
-
logger.
|
|
56
|
+
logger.debug(`Found and processed Zod schema: ${schemaName}`);
|
|
56
57
|
this.openapiDefinitions[schemaName] = zodSchema;
|
|
57
58
|
return zodSchema;
|
|
58
59
|
}
|
|
59
|
-
logger.
|
|
60
|
+
logger.debug(`No Zod schema found for ${schemaName}, trying TypeScript fallback`);
|
|
60
61
|
}
|
|
61
62
|
// Fall back to TypeScript types
|
|
62
63
|
this.scanSchemaDir(this.schemaDir, schemaName);
|
|
@@ -166,10 +167,21 @@ export class SchemaProcessor {
|
|
|
166
167
|
const enumValues = this.processEnum(typeNode);
|
|
167
168
|
return enumValues;
|
|
168
169
|
}
|
|
169
|
-
if (t.isTSTypeLiteral(typeNode) || t.isTSInterfaceBody(typeNode)) {
|
|
170
|
+
if (t.isTSTypeLiteral(typeNode) || t.isTSInterfaceBody(typeNode) || t.isTSInterfaceDeclaration(typeNode)) {
|
|
170
171
|
const properties = {};
|
|
171
|
-
|
|
172
|
-
|
|
172
|
+
// Handle interface extends clause
|
|
173
|
+
if (t.isTSInterfaceDeclaration(typeNode) && typeNode.extends && typeNode.extends.length > 0) {
|
|
174
|
+
typeNode.extends.forEach((extendedType) => {
|
|
175
|
+
const extendedSchema = this.resolveTSNodeType(extendedType);
|
|
176
|
+
if (extendedSchema.properties) {
|
|
177
|
+
Object.assign(properties, extendedSchema.properties);
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
// Get members from interface declaration body or direct members
|
|
182
|
+
const members = t.isTSInterfaceDeclaration(typeNode) ? typeNode.body.body : typeNode.members;
|
|
183
|
+
if (members) {
|
|
184
|
+
(members || []).forEach((member) => {
|
|
173
185
|
if (t.isTSPropertySignature(member) && t.isIdentifier(member.key)) {
|
|
174
186
|
const propName = member.key.name;
|
|
175
187
|
const options = this.getPropertyOptions(member);
|
|
@@ -192,6 +204,9 @@ export class SchemaProcessor {
|
|
|
192
204
|
if (t.isTSUnionType(typeNode)) {
|
|
193
205
|
return this.resolveTSNodeType(typeNode);
|
|
194
206
|
}
|
|
207
|
+
if (t.isTSTypeReference(typeNode)) {
|
|
208
|
+
return this.resolveTSNodeType(typeNode);
|
|
209
|
+
}
|
|
195
210
|
return {};
|
|
196
211
|
}
|
|
197
212
|
finally {
|
|
@@ -250,6 +265,18 @@ export class SchemaProcessor {
|
|
|
250
265
|
};
|
|
251
266
|
}
|
|
252
267
|
}
|
|
268
|
+
// Handle TSExpressionWithTypeArguments (used in interface extends)
|
|
269
|
+
if (t.isTSExpressionWithTypeArguments(node)) {
|
|
270
|
+
if (t.isIdentifier(node.expression)) {
|
|
271
|
+
// Convert to TSTypeReference-like structure for processing
|
|
272
|
+
const syntheticNode = {
|
|
273
|
+
type: 'TSTypeReference',
|
|
274
|
+
typeName: node.expression,
|
|
275
|
+
typeParameters: node.typeParameters
|
|
276
|
+
};
|
|
277
|
+
return this.resolveTSNodeType(syntheticNode);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
253
280
|
if (t.isTSTypeReference(node) && t.isIdentifier(node.typeName)) {
|
|
254
281
|
const typeName = node.typeName.name;
|
|
255
282
|
// Special handling for built-in types
|
|
@@ -284,6 +311,34 @@ export class SchemaProcessor {
|
|
|
284
311
|
}
|
|
285
312
|
}
|
|
286
313
|
if (typeName === "Pick" || typeName === "Omit") {
|
|
314
|
+
if (node.typeParameters && node.typeParameters.params.length > 1) {
|
|
315
|
+
const baseTypeParam = node.typeParameters.params[0];
|
|
316
|
+
const keysParam = node.typeParameters.params[1];
|
|
317
|
+
// Resolve base type without adding it to schema definitions
|
|
318
|
+
this.isResolvingPickOmitBase = true;
|
|
319
|
+
const baseType = this.resolveTSNodeType(baseTypeParam);
|
|
320
|
+
this.isResolvingPickOmitBase = false;
|
|
321
|
+
if (baseType.properties) {
|
|
322
|
+
const properties = {};
|
|
323
|
+
const keyNames = this.extractKeysFromLiteralType(keysParam);
|
|
324
|
+
if (typeName === "Pick") {
|
|
325
|
+
keyNames.forEach(key => {
|
|
326
|
+
if (baseType.properties[key]) {
|
|
327
|
+
properties[key] = baseType.properties[key];
|
|
328
|
+
}
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
else { // Omit
|
|
332
|
+
Object.entries(baseType.properties).forEach(([key, value]) => {
|
|
333
|
+
if (!keyNames.includes(key)) {
|
|
334
|
+
properties[key] = value;
|
|
335
|
+
}
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
return { type: "object", properties };
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
// Fallback to just the base type if we can't process properly
|
|
287
342
|
if (node.typeParameters && node.typeParameters.params.length > 0) {
|
|
288
343
|
return this.resolveTSNodeType(node.typeParameters.params[0]);
|
|
289
344
|
}
|
|
@@ -395,7 +450,7 @@ export class SchemaProcessor {
|
|
|
395
450
|
if (t.isTSTypeReference(node) && t.isIdentifier(node.typeName)) {
|
|
396
451
|
return { $ref: `#/components/schemas/${node.typeName.name}` };
|
|
397
452
|
}
|
|
398
|
-
logger.
|
|
453
|
+
logger.debug("Unrecognized TypeScript type node:", node);
|
|
399
454
|
return { type: "object" }; // By default we return an object
|
|
400
455
|
}
|
|
401
456
|
processSchemaFile(filePath, schemaName) {
|
|
@@ -413,7 +468,9 @@ export class SchemaProcessor {
|
|
|
413
468
|
// Reset the set of processed types before each schema processing
|
|
414
469
|
this.processingTypes.clear();
|
|
415
470
|
const definition = this.resolveType(schemaName);
|
|
416
|
-
this.
|
|
471
|
+
if (!this.isResolvingPickOmitBase) {
|
|
472
|
+
this.openapiDefinitions[schemaName] = definition;
|
|
473
|
+
}
|
|
417
474
|
this.processSchemaTracker[`${filePath}-${schemaName}`] = true;
|
|
418
475
|
return definition;
|
|
419
476
|
}
|
|
@@ -447,6 +504,21 @@ export class SchemaProcessor {
|
|
|
447
504
|
});
|
|
448
505
|
return enumSchema;
|
|
449
506
|
}
|
|
507
|
+
extractKeysFromLiteralType(node) {
|
|
508
|
+
if (t.isTSLiteralType(node) && t.isStringLiteral(node.literal)) {
|
|
509
|
+
return [node.literal.value];
|
|
510
|
+
}
|
|
511
|
+
if (t.isTSUnionType(node)) {
|
|
512
|
+
const keys = [];
|
|
513
|
+
node.types.forEach((type) => {
|
|
514
|
+
if (t.isTSLiteralType(type) && t.isStringLiteral(type.literal)) {
|
|
515
|
+
keys.push(type.literal.value);
|
|
516
|
+
}
|
|
517
|
+
});
|
|
518
|
+
return keys;
|
|
519
|
+
}
|
|
520
|
+
return [];
|
|
521
|
+
}
|
|
450
522
|
getPropertyOptions(node) {
|
|
451
523
|
const isOptional = !!node.optional; // check if property is optional
|
|
452
524
|
let description = null;
|
|
@@ -24,11 +24,11 @@ export class ZodSchemaConverter {
|
|
|
24
24
|
if (Object.keys(this.typeToSchemaMapping).length === 0) {
|
|
25
25
|
this.preScanForTypeMappings();
|
|
26
26
|
}
|
|
27
|
-
logger.
|
|
27
|
+
logger.debug(`Looking for Zod schema: ${schemaName}`);
|
|
28
28
|
// Check mapped types
|
|
29
29
|
const mappedSchemaName = this.typeToSchemaMapping[schemaName];
|
|
30
30
|
if (mappedSchemaName) {
|
|
31
|
-
logger.
|
|
31
|
+
logger.debug(`Type '${schemaName}' is mapped to schema '${mappedSchemaName}'`);
|
|
32
32
|
schemaName = mappedSchemaName;
|
|
33
33
|
}
|
|
34
34
|
// Check for circular references
|
|
@@ -47,7 +47,7 @@ export class ZodSchemaConverter {
|
|
|
47
47
|
for (const routeFile of routeFiles) {
|
|
48
48
|
this.processFileForZodSchema(routeFile, schemaName);
|
|
49
49
|
if (this.zodSchemas[schemaName]) {
|
|
50
|
-
logger.
|
|
50
|
+
logger.debug(`Found Zod schema '${schemaName}' in route file: ${routeFile}`);
|
|
51
51
|
return this.zodSchemas[schemaName];
|
|
52
52
|
}
|
|
53
53
|
}
|
|
@@ -55,10 +55,10 @@ export class ZodSchemaConverter {
|
|
|
55
55
|
this.scanDirectoryForZodSchema(this.schemaDir, schemaName);
|
|
56
56
|
// Return the schema if found, or null if not
|
|
57
57
|
if (this.zodSchemas[schemaName]) {
|
|
58
|
-
logger.
|
|
58
|
+
logger.debug(`Found and processed Zod schema: ${schemaName}`);
|
|
59
59
|
return this.zodSchemas[schemaName];
|
|
60
60
|
}
|
|
61
|
-
logger.
|
|
61
|
+
logger.debug(`Could not find Zod schema: ${schemaName}`);
|
|
62
62
|
return null;
|
|
63
63
|
}
|
|
64
64
|
finally {
|
|
@@ -105,7 +105,7 @@ export class ZodSchemaConverter {
|
|
|
105
105
|
}
|
|
106
106
|
}
|
|
107
107
|
catch (error) {
|
|
108
|
-
logger.
|
|
108
|
+
logger.error(`Error scanning directory ${dir} for route files: ${error}`);
|
|
109
109
|
}
|
|
110
110
|
}
|
|
111
111
|
/**
|
|
@@ -126,7 +126,7 @@ export class ZodSchemaConverter {
|
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
128
|
catch (error) {
|
|
129
|
-
logger.
|
|
129
|
+
logger.error(`Error scanning directory ${dir}: ${error}`);
|
|
130
130
|
}
|
|
131
131
|
}
|
|
132
132
|
/**
|
|
@@ -273,7 +273,7 @@ export class ZodSchemaConverter {
|
|
|
273
273
|
? prop.key.value
|
|
274
274
|
: null;
|
|
275
275
|
if (key && schema.properties) {
|
|
276
|
-
logger.
|
|
276
|
+
logger.debug(`Removing property: ${key}`);
|
|
277
277
|
delete schema.properties[key];
|
|
278
278
|
if (schema.required) {
|
|
279
279
|
schema.required = schema.required.filter((r) => r !== key);
|
|
@@ -358,20 +358,20 @@ export class ZodSchemaConverter {
|
|
|
358
358
|
if (t.isCallExpression(path.node.init)) {
|
|
359
359
|
const baseSchemaName = findBaseSchema(path.node.init);
|
|
360
360
|
if (baseSchemaName && baseSchemaName !== "z") {
|
|
361
|
-
logger.
|
|
361
|
+
logger.debug(`Found chained call starting from: ${baseSchemaName}`);
|
|
362
362
|
// First make sure the underlying schema is processed
|
|
363
363
|
if (!this.zodSchemas[baseSchemaName]) {
|
|
364
|
-
logger.
|
|
364
|
+
logger.debug(`Base schema ${baseSchemaName} not found, processing it first`);
|
|
365
365
|
this.processFileForZodSchema(filePath, baseSchemaName);
|
|
366
366
|
}
|
|
367
367
|
if (this.zodSchemas[baseSchemaName]) {
|
|
368
|
-
logger.
|
|
368
|
+
logger.debug("Base schema found, applying transformations");
|
|
369
369
|
// Copy base schema
|
|
370
370
|
const baseSchema = JSON.parse(JSON.stringify(this.zodSchemas[baseSchemaName]));
|
|
371
371
|
// Process the entire call chain
|
|
372
372
|
const finalSchema = processChainedCall(path.node.init, baseSchema);
|
|
373
373
|
this.zodSchemas[schemaName] = finalSchema;
|
|
374
|
-
logger.
|
|
374
|
+
logger.debug(`Created ${schemaName} with properties: ${Object.keys(finalSchema.properties || {})}`);
|
|
375
375
|
return;
|
|
376
376
|
}
|
|
377
377
|
}
|
|
@@ -413,7 +413,7 @@ export class ZodSchemaConverter {
|
|
|
413
413
|
const referencedSchemaName = param.exprName.name;
|
|
414
414
|
// Save mapping: TypeName -> SchemaName
|
|
415
415
|
this.typeToSchemaMapping[typeName] = referencedSchemaName;
|
|
416
|
-
logger.
|
|
416
|
+
logger.debug(`Mapped type '${typeName}' to schema '${referencedSchemaName}'`);
|
|
417
417
|
// Process the referenced schema if not already processed
|
|
418
418
|
if (!this.zodSchemas[referencedSchemaName]) {
|
|
419
419
|
this.processFileForZodSchema(filePath, referencedSchemaName);
|
|
@@ -450,7 +450,7 @@ export class ZodSchemaConverter {
|
|
|
450
450
|
});
|
|
451
451
|
}
|
|
452
452
|
catch (error) {
|
|
453
|
-
|
|
453
|
+
logger.error(`Error processing file ${filePath} for schema ${schemaName}: ${error}`);
|
|
454
454
|
}
|
|
455
455
|
}
|
|
456
456
|
/**
|
|
@@ -490,7 +490,7 @@ export class ZodSchemaConverter {
|
|
|
490
490
|
});
|
|
491
491
|
}
|
|
492
492
|
catch (error) {
|
|
493
|
-
|
|
493
|
+
logger.error(`Error processing all schemas in file ${filePath}: ${error}`);
|
|
494
494
|
}
|
|
495
495
|
}
|
|
496
496
|
/**
|
|
@@ -557,7 +557,7 @@ export class ZodSchemaConverter {
|
|
|
557
557
|
node.arguments.length > 0) {
|
|
558
558
|
return this.processZodLazy(node);
|
|
559
559
|
}
|
|
560
|
-
|
|
560
|
+
logger.debug("Unknown Zod schema node:", node);
|
|
561
561
|
return { type: "object" };
|
|
562
562
|
}
|
|
563
563
|
/**
|
|
@@ -736,7 +736,7 @@ export class ZodSchemaConverter {
|
|
|
736
736
|
propName = prop.key.value;
|
|
737
737
|
}
|
|
738
738
|
else {
|
|
739
|
-
|
|
739
|
+
logger.debug(`Skipping property ${index} - unsupported key type`);
|
|
740
740
|
return; // Skip if key is not identifier or string literal
|
|
741
741
|
}
|
|
742
742
|
if (t.isCallExpression(prop.value) &&
|
|
@@ -1223,7 +1223,7 @@ export class ZodSchemaConverter {
|
|
|
1223
1223
|
schema.description = baseSchema.description;
|
|
1224
1224
|
}
|
|
1225
1225
|
else {
|
|
1226
|
-
logger.
|
|
1226
|
+
logger.debug("Could not resolve base schema for extend");
|
|
1227
1227
|
schema = extendedProps || { type: "object" };
|
|
1228
1228
|
}
|
|
1229
1229
|
}
|
|
@@ -1314,7 +1314,7 @@ export class ZodSchemaConverter {
|
|
|
1314
1314
|
* Pre-scan all files to build type mappings
|
|
1315
1315
|
*/
|
|
1316
1316
|
preScanForTypeMappings() {
|
|
1317
|
-
logger.
|
|
1317
|
+
logger.debug("Pre-scanning for type mappings...");
|
|
1318
1318
|
// Scan route files
|
|
1319
1319
|
const routeFiles = this.findRouteFiles();
|
|
1320
1320
|
for (const routeFile of routeFiles) {
|
|
@@ -1360,7 +1360,7 @@ export class ZodSchemaConverter {
|
|
|
1360
1360
|
if (t.isTSTypeQuery(param) && t.isIdentifier(param.exprName)) {
|
|
1361
1361
|
const referencedSchemaName = param.exprName.name;
|
|
1362
1362
|
this.typeToSchemaMapping[typeName] = referencedSchemaName;
|
|
1363
|
-
logger.
|
|
1363
|
+
logger.debug(`Pre-scan: Mapped type '${typeName}' to schema '${referencedSchemaName}'`);
|
|
1364
1364
|
}
|
|
1365
1365
|
}
|
|
1366
1366
|
}
|
|
@@ -1369,7 +1369,7 @@ export class ZodSchemaConverter {
|
|
|
1369
1369
|
});
|
|
1370
1370
|
}
|
|
1371
1371
|
catch (error) {
|
|
1372
|
-
logger.
|
|
1372
|
+
logger.error(`Error scanning file ${filePath} for type mappings: ${error}`);
|
|
1373
1373
|
}
|
|
1374
1374
|
}
|
|
1375
1375
|
/**
|
|
@@ -1413,7 +1413,7 @@ export class ZodSchemaConverter {
|
|
|
1413
1413
|
// Check if is Zos schema
|
|
1414
1414
|
if (this.isZodSchema(declaration.init) &&
|
|
1415
1415
|
!this.zodSchemas[schemaName]) {
|
|
1416
|
-
logger.
|
|
1416
|
+
logger.debug(`Pre-processing Zod schema: ${schemaName}`);
|
|
1417
1417
|
this.processingSchemas.add(schemaName);
|
|
1418
1418
|
const schema = this.processZodNode(declaration.init);
|
|
1419
1419
|
if (schema) {
|
|
@@ -1433,7 +1433,7 @@ export class ZodSchemaConverter {
|
|
|
1433
1433
|
if (this.isZodSchema(declaration.init) &&
|
|
1434
1434
|
!this.zodSchemas[schemaName] &&
|
|
1435
1435
|
!this.processingSchemas.has(schemaName)) {
|
|
1436
|
-
logger.
|
|
1436
|
+
logger.debug(`Pre-processing Zod schema: ${schemaName}`);
|
|
1437
1437
|
this.processingSchemas.add(schemaName);
|
|
1438
1438
|
const schema = this.processZodNode(declaration.init);
|
|
1439
1439
|
if (schema) {
|
package/package.json
CHANGED