@hanseltime/template-repo-sync 1.0.1 → 1.2.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/CHANGELOG.md +14 -0
- package/README.md +80 -3
- package/docs/merge-plugins/CURRENT_PLUGINS.md +168 -0
- package/docs/merge-plugins/DEVELOPMENT.md +129 -0
- package/docs/merge-plugins/README.md +85 -0
- package/lib/cjs/plugins/json-merge.js +30 -7
- package/lib/cjs/ref-drivers/git-current-ref.d.ts +3 -0
- package/lib/cjs/ref-drivers/git-current-ref.js +12 -0
- package/lib/cjs/ref-drivers/index.d.ts +1 -0
- package/lib/cjs/ref-drivers/index.js +17 -0
- package/lib/cjs/ref-drivers/types.d.ts +10 -0
- package/lib/cjs/ref-drivers/types.js +2 -0
- package/lib/cjs/template-sync.d.ts +10 -0
- package/lib/cjs/template-sync.js +46 -4
- package/lib/cjs/types.d.ts +1 -1
- package/lib/esm/plugins/json-merge.js +30 -7
- package/lib/esm/ref-drivers/git-current-ref.js +12 -0
- package/lib/esm/ref-drivers/index.js +17 -0
- package/lib/esm/ref-drivers/types.js +2 -0
- package/lib/esm/template-sync.js +46 -4
- package/package.json +5 -8
- package/src/plugins/json-merge.spec.ts +86 -0
- package/src/plugins/json-merge.ts +17 -7
- package/src/ref-drivers/git-current-ref.spec.ts +12 -0
- package/src/ref-drivers/git-current-ref.ts +9 -0
- package/src/ref-drivers/index.ts +1 -0
- package/src/ref-drivers/types.ts +10 -0
- package/src/template-sync.spec.ts +121 -0
- package/src/template-sync.ts +48 -6
- package/src/types.ts +1 -1
package/lib/cjs/template-sync.js
CHANGED
|
@@ -1,4 +1,27 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
2
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
26
|
exports.templateSync = exports.TEMPLATE_SYNC_LOCAL_CONFIG = exports.TEMPLATE_SYNC_CONFIG = void 0;
|
|
4
27
|
const path_1 = require("path");
|
|
@@ -7,21 +30,25 @@ const match_1 = require("./match");
|
|
|
7
30
|
const merge_file_1 = require("./merge-file");
|
|
8
31
|
const git_clone_1 = require("./clone-drivers/git-clone");
|
|
9
32
|
const diff_drivers_1 = require("./diff-drivers");
|
|
33
|
+
const ref_drivers_1 = require("./ref-drivers");
|
|
34
|
+
const formatting_1 = require("./formatting");
|
|
35
|
+
const commentJSON = __importStar(require("comment-json"));
|
|
10
36
|
exports.TEMPLATE_SYNC_CONFIG = "templatesync";
|
|
11
37
|
exports.TEMPLATE_SYNC_LOCAL_CONFIG = "templatesync.local";
|
|
12
38
|
async function templateSync(options) {
|
|
13
39
|
const cloneDriver = options.cloneDriver ?? git_clone_1.gitClone;
|
|
14
40
|
const diffDriver = options.diffDriver ?? diff_drivers_1.gitDiff;
|
|
41
|
+
const currentRefDriver = options.currentRefDriver ?? ref_drivers_1.gitCurrentRef;
|
|
15
42
|
const tempCloneDir = await cloneDriver(options.tmpCloneDir, options.repoUrl);
|
|
16
43
|
// Get the clone Config
|
|
17
44
|
const cloneConfigPath = (0, path_1.join)(tempCloneDir, `${exports.TEMPLATE_SYNC_CONFIG}.json`);
|
|
18
45
|
const templateSyncConfig = (0, fs_1.existsSync)(cloneConfigPath)
|
|
19
|
-
?
|
|
20
|
-
: {};
|
|
46
|
+
? commentJSON.parse((0, fs_1.readFileSync)(cloneConfigPath).toString())
|
|
47
|
+
: { ignore: [] };
|
|
21
48
|
const localConfigPath = (0, path_1.join)(options.repoDir, `${exports.TEMPLATE_SYNC_LOCAL_CONFIG}.json`);
|
|
22
49
|
const localTemplateSyncConfig = (0, fs_1.existsSync)(localConfigPath)
|
|
23
|
-
?
|
|
24
|
-
: {};
|
|
50
|
+
? commentJSON.parse((0, fs_1.readFileSync)(localConfigPath).toString())
|
|
51
|
+
: { ignore: [] };
|
|
25
52
|
let filesToSync;
|
|
26
53
|
if (localTemplateSyncConfig.afterRef) {
|
|
27
54
|
filesToSync = await diffDriver(tempCloneDir, localTemplateSyncConfig.afterRef);
|
|
@@ -48,6 +75,21 @@ async function templateSync(options) {
|
|
|
48
75
|
localFileChanges[f] = result.localChanges;
|
|
49
76
|
}
|
|
50
77
|
}));
|
|
78
|
+
// apply after ref
|
|
79
|
+
if (options.updateAfterRef) {
|
|
80
|
+
const ref = await currentRefDriver({
|
|
81
|
+
rootDir: tempCloneDir,
|
|
82
|
+
});
|
|
83
|
+
if ((0, fs_1.existsSync)(localConfigPath)) {
|
|
84
|
+
const configStr = (0, fs_1.readFileSync)(localConfigPath).toString();
|
|
85
|
+
const config = commentJSON.parse(configStr);
|
|
86
|
+
config.afterRef = ref;
|
|
87
|
+
(0, fs_1.writeFileSync)(localConfigPath, commentJSON.stringify(config, null, (0, formatting_1.inferJSONIndent)(configStr)));
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
(0, fs_1.writeFileSync)(localConfigPath, commentJSON.stringify({ afterRef: ref }, null, 4));
|
|
91
|
+
}
|
|
92
|
+
}
|
|
51
93
|
return {
|
|
52
94
|
localSkipFiles,
|
|
53
95
|
localFileChanges,
|
package/lib/cjs/types.d.ts
CHANGED
|
@@ -1,13 +1,36 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
2
25
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
26
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
27
|
};
|
|
5
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
29
|
exports.merge = exports.validate = void 0;
|
|
7
30
|
const lodash_merge_1 = __importDefault(require("lodash.merge"));
|
|
8
|
-
const lodash_clonedeep_1 = __importDefault(require("lodash.clonedeep"));
|
|
9
31
|
const jsonpath_1 = __importDefault(require("jsonpath"));
|
|
10
32
|
const infer_json_indent_1 = require("../formatting/infer-json-indent");
|
|
33
|
+
const commentJSON = __importStar(require("comment-json"));
|
|
11
34
|
function stringOptionError(value) {
|
|
12
35
|
if (value === "overwrite" ||
|
|
13
36
|
value === "merge-template" ||
|
|
@@ -78,18 +101,18 @@ async function merge(current, fromTemplateRepo, context) {
|
|
|
78
101
|
if (context.mergeArguments === "overwrite") {
|
|
79
102
|
return fromTemplateRepo;
|
|
80
103
|
}
|
|
81
|
-
const currentJson =
|
|
82
|
-
const fromTemplateJson =
|
|
104
|
+
const currentJson = commentJSON.parse(current);
|
|
105
|
+
const fromTemplateJson = commentJSON.parse(fromTemplateRepo);
|
|
83
106
|
if (context.mergeArguments === "merge-current") {
|
|
84
107
|
// Performs Lodash Merge with current as the override
|
|
85
|
-
return
|
|
108
|
+
return commentJSON.stringify((0, lodash_merge_1.default)(fromTemplateJson, currentJson), null, (0, infer_json_indent_1.inferJSONIndent)(current));
|
|
86
109
|
}
|
|
87
110
|
if (context.mergeArguments === "merge-template") {
|
|
88
111
|
// Performs Lodash Merge with current as the override
|
|
89
|
-
return
|
|
112
|
+
return commentJSON.stringify((0, lodash_merge_1.default)(currentJson, fromTemplateJson), null, (0, infer_json_indent_1.inferJSONIndent)(current));
|
|
90
113
|
}
|
|
91
114
|
const { missingIsDelete, ignoreNewProperties, paths } = context.mergeArguments;
|
|
92
|
-
const returnJson =
|
|
115
|
+
const returnJson = commentJSON.parse(current);
|
|
93
116
|
paths.forEach((p) => {
|
|
94
117
|
const [jPath, overrideType] = p;
|
|
95
118
|
const fromTemplatePaths = new Map();
|
|
@@ -143,7 +166,7 @@ async function merge(current, fromTemplateRepo, context) {
|
|
|
143
166
|
}
|
|
144
167
|
});
|
|
145
168
|
}
|
|
146
|
-
return
|
|
169
|
+
return commentJSON.stringify(returnJson, null, (0, infer_json_indent_1.inferJSONIndent)(current));
|
|
147
170
|
}
|
|
148
171
|
exports.merge = merge;
|
|
149
172
|
/**
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.gitCurrentRef = void 0;
|
|
4
|
+
const child_process_1 = require("child_process");
|
|
5
|
+
async function gitCurrentRef(options) {
|
|
6
|
+
return (0, child_process_1.execSync)(`git rev-parse HEAD`, {
|
|
7
|
+
cwd: options.rootDir,
|
|
8
|
+
})
|
|
9
|
+
.toString()
|
|
10
|
+
.trim();
|
|
11
|
+
}
|
|
12
|
+
exports.gitCurrentRef = gitCurrentRef;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./git-current-ref"), exports);
|
package/lib/esm/template-sync.js
CHANGED
|
@@ -1,4 +1,27 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
2
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
26
|
exports.templateSync = exports.TEMPLATE_SYNC_LOCAL_CONFIG = exports.TEMPLATE_SYNC_CONFIG = void 0;
|
|
4
27
|
const path_1 = require("path");
|
|
@@ -7,21 +30,25 @@ const match_1 = require("./match");
|
|
|
7
30
|
const merge_file_1 = require("./merge-file");
|
|
8
31
|
const git_clone_1 = require("./clone-drivers/git-clone");
|
|
9
32
|
const diff_drivers_1 = require("./diff-drivers");
|
|
33
|
+
const ref_drivers_1 = require("./ref-drivers");
|
|
34
|
+
const formatting_1 = require("./formatting");
|
|
35
|
+
const commentJSON = __importStar(require("comment-json"));
|
|
10
36
|
exports.TEMPLATE_SYNC_CONFIG = "templatesync";
|
|
11
37
|
exports.TEMPLATE_SYNC_LOCAL_CONFIG = "templatesync.local";
|
|
12
38
|
async function templateSync(options) {
|
|
13
39
|
const cloneDriver = options.cloneDriver ?? git_clone_1.gitClone;
|
|
14
40
|
const diffDriver = options.diffDriver ?? diff_drivers_1.gitDiff;
|
|
41
|
+
const currentRefDriver = options.currentRefDriver ?? ref_drivers_1.gitCurrentRef;
|
|
15
42
|
const tempCloneDir = await cloneDriver(options.tmpCloneDir, options.repoUrl);
|
|
16
43
|
// Get the clone Config
|
|
17
44
|
const cloneConfigPath = (0, path_1.join)(tempCloneDir, `${exports.TEMPLATE_SYNC_CONFIG}.json`);
|
|
18
45
|
const templateSyncConfig = (0, fs_1.existsSync)(cloneConfigPath)
|
|
19
|
-
?
|
|
20
|
-
: {};
|
|
46
|
+
? commentJSON.parse((0, fs_1.readFileSync)(cloneConfigPath).toString())
|
|
47
|
+
: { ignore: [] };
|
|
21
48
|
const localConfigPath = (0, path_1.join)(options.repoDir, `${exports.TEMPLATE_SYNC_LOCAL_CONFIG}.json`);
|
|
22
49
|
const localTemplateSyncConfig = (0, fs_1.existsSync)(localConfigPath)
|
|
23
|
-
?
|
|
24
|
-
: {};
|
|
50
|
+
? commentJSON.parse((0, fs_1.readFileSync)(localConfigPath).toString())
|
|
51
|
+
: { ignore: [] };
|
|
25
52
|
let filesToSync;
|
|
26
53
|
if (localTemplateSyncConfig.afterRef) {
|
|
27
54
|
filesToSync = await diffDriver(tempCloneDir, localTemplateSyncConfig.afterRef);
|
|
@@ -48,6 +75,21 @@ async function templateSync(options) {
|
|
|
48
75
|
localFileChanges[f] = result.localChanges;
|
|
49
76
|
}
|
|
50
77
|
}));
|
|
78
|
+
// apply after ref
|
|
79
|
+
if (options.updateAfterRef) {
|
|
80
|
+
const ref = await currentRefDriver({
|
|
81
|
+
rootDir: tempCloneDir,
|
|
82
|
+
});
|
|
83
|
+
if ((0, fs_1.existsSync)(localConfigPath)) {
|
|
84
|
+
const configStr = (0, fs_1.readFileSync)(localConfigPath).toString();
|
|
85
|
+
const config = commentJSON.parse(configStr);
|
|
86
|
+
config.afterRef = ref;
|
|
87
|
+
(0, fs_1.writeFileSync)(localConfigPath, commentJSON.stringify(config, null, (0, formatting_1.inferJSONIndent)(configStr)));
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
(0, fs_1.writeFileSync)(localConfigPath, commentJSON.stringify({ afterRef: ref }, null, 4));
|
|
91
|
+
}
|
|
92
|
+
}
|
|
51
93
|
return {
|
|
52
94
|
localSkipFiles,
|
|
53
95
|
localFileChanges,
|
package/package.json
CHANGED
|
@@ -1,29 +1,27 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hanseltime/template-repo-sync",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "An npm library that enables pluggable, customizable synchronization between template repos",
|
|
5
5
|
"main": "lib/cjs/index.js",
|
|
6
6
|
"types": "lib/cjs/index.d.ts",
|
|
7
7
|
"module": "lib/esm/index.js",
|
|
8
8
|
"scripts": {
|
|
9
|
-
"format": "
|
|
10
|
-
"lint": "
|
|
9
|
+
"format": "prettier . --write",
|
|
10
|
+
"lint": "eslint .",
|
|
11
11
|
"test": "NODE_OPTIONS=\"$NODE_OPTIONS --experimental-vm-modules\" jest",
|
|
12
12
|
"run-script": "node --loader ts-node/esm",
|
|
13
13
|
"build": "tsc -p tsconfig.cjs.json && tsc -p tsconfig.esm.json",
|
|
14
14
|
"prepare": "husky",
|
|
15
|
-
"release": "
|
|
15
|
+
"release": "semantic-release"
|
|
16
16
|
},
|
|
17
17
|
"keywords": [],
|
|
18
18
|
"author": "",
|
|
19
19
|
"license": "ISC",
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"
|
|
22
|
-
"@actions/github": "^6.0.0",
|
|
21
|
+
"comment-json": "^4.2.3",
|
|
23
22
|
"diff": "^5.1.0",
|
|
24
23
|
"fs-extra": "^11.2.0",
|
|
25
24
|
"jsonpath": "^1.1.1",
|
|
26
|
-
"lodash.clonedeep": "^4.5.0",
|
|
27
25
|
"lodash.merge": "^4.6.2",
|
|
28
26
|
"micromatch": "^4.0.5"
|
|
29
27
|
},
|
|
@@ -35,7 +33,6 @@
|
|
|
35
33
|
"@types/fs-extra": "^11.0.4",
|
|
36
34
|
"@types/jest": "^29.5.11",
|
|
37
35
|
"@types/jsonpath": "^0.2.4",
|
|
38
|
-
"@types/lodash.clonedeep": "^4.5.9",
|
|
39
36
|
"@types/lodash.merge": "^4.6.9",
|
|
40
37
|
"@types/micromatch": "^4.0.6",
|
|
41
38
|
"@types/node": "^20.11.7",
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
2
|
import { JsonPathOverrides } from "../types";
|
|
3
3
|
import { merge, validate } from "./json-merge";
|
|
4
|
+
import * as commentJson from "comment-json";
|
|
4
5
|
|
|
5
6
|
const testFileJson = {
|
|
6
7
|
here: "here",
|
|
@@ -24,6 +25,21 @@ const templateFileJson = {
|
|
|
24
25
|
},
|
|
25
26
|
};
|
|
26
27
|
|
|
28
|
+
const testCommentJson = `{
|
|
29
|
+
// This is a top comment
|
|
30
|
+
"here": "here",
|
|
31
|
+
"another": 23, // this is inline
|
|
32
|
+
"inner": {
|
|
33
|
+
"el1": "el1",
|
|
34
|
+
"arr1": ["a1", "a2"],
|
|
35
|
+
"nested": {
|
|
36
|
+
// Upper comment
|
|
37
|
+
"final": "final", // Inline commment
|
|
38
|
+
"final2": "final2",
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
}`;
|
|
42
|
+
|
|
27
43
|
describe("merge", () => {
|
|
28
44
|
it("performs overwrite when specified", async () => {
|
|
29
45
|
const fromTemplateJson = {
|
|
@@ -291,6 +307,76 @@ describe("merge", () => {
|
|
|
291
307
|
},
|
|
292
308
|
});
|
|
293
309
|
});
|
|
310
|
+
it("performs pathjson merges on comment json", async () => {
|
|
311
|
+
const template = { ...templateFileJson };
|
|
312
|
+
(template.inner as any).nested = {
|
|
313
|
+
final: { something: 44 },
|
|
314
|
+
newThing: "this",
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
const testTemplateCommentJson = `{
|
|
318
|
+
"here": "heretemplate",
|
|
319
|
+
/** New comment explaining extra **/
|
|
320
|
+
"extra": "extra",
|
|
321
|
+
"inner": {
|
|
322
|
+
"arr1": ["b1", "b2"],
|
|
323
|
+
"extra2": "extra2",
|
|
324
|
+
"nested": {
|
|
325
|
+
"final": {
|
|
326
|
+
// New comment explaining final
|
|
327
|
+
"something": 44,
|
|
328
|
+
},
|
|
329
|
+
"newThing": {
|
|
330
|
+
// new thing comment
|
|
331
|
+
"this": 23,
|
|
332
|
+
},
|
|
333
|
+
}
|
|
334
|
+
},
|
|
335
|
+
}`;
|
|
336
|
+
|
|
337
|
+
expect(
|
|
338
|
+
commentJson.stringify(
|
|
339
|
+
commentJson.parse(
|
|
340
|
+
await merge(testCommentJson, testTemplateCommentJson, {
|
|
341
|
+
relFilePath: "somepath",
|
|
342
|
+
mergeArguments: {
|
|
343
|
+
paths: [
|
|
344
|
+
["$.here", "merge-template"],
|
|
345
|
+
["$.inner.nested.*", "merge-template"],
|
|
346
|
+
["$.inner.nested.final", "merge-current"],
|
|
347
|
+
],
|
|
348
|
+
},
|
|
349
|
+
}),
|
|
350
|
+
),
|
|
351
|
+
null,
|
|
352
|
+
4,
|
|
353
|
+
),
|
|
354
|
+
).toEqual(
|
|
355
|
+
commentJson.stringify(
|
|
356
|
+
commentJson.parse(`{
|
|
357
|
+
// This is a top comment
|
|
358
|
+
"here": "heretemplate",
|
|
359
|
+
"another": 23, // this is inline
|
|
360
|
+
"inner": {
|
|
361
|
+
"el1": "el1",
|
|
362
|
+
"arr1": ["a1", "a2"],
|
|
363
|
+
"nested": {
|
|
364
|
+
// Upper comment
|
|
365
|
+
"final": "final", // Inline commment
|
|
366
|
+
"final2": "final2",
|
|
367
|
+
"newThing": {
|
|
368
|
+
// new thing comment
|
|
369
|
+
"this": 23,
|
|
370
|
+
},
|
|
371
|
+
},
|
|
372
|
+
},
|
|
373
|
+
"extra": "extra",
|
|
374
|
+
}`),
|
|
375
|
+
null,
|
|
376
|
+
4,
|
|
377
|
+
),
|
|
378
|
+
);
|
|
379
|
+
});
|
|
294
380
|
});
|
|
295
381
|
|
|
296
382
|
describe("validate", () => {
|
|
@@ -4,9 +4,9 @@ import {
|
|
|
4
4
|
JsonPathOverrides,
|
|
5
5
|
} from "../types";
|
|
6
6
|
import lodashMerge from "lodash.merge";
|
|
7
|
-
import locashCloneDeep from "lodash.clonedeep";
|
|
8
7
|
import jp, { PathComponent } from "jsonpath";
|
|
9
8
|
import { inferJSONIndent } from "../formatting/infer-json-indent";
|
|
9
|
+
import * as commentJSON from "comment-json";
|
|
10
10
|
|
|
11
11
|
function stringOptionError(value: string) {
|
|
12
12
|
if (
|
|
@@ -88,23 +88,33 @@ export async function merge(
|
|
|
88
88
|
return fromTemplateRepo;
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
-
const currentJson =
|
|
92
|
-
const fromTemplateJson =
|
|
91
|
+
const currentJson = commentJSON.parse(current) as commentJSON.CommentObject;
|
|
92
|
+
const fromTemplateJson = commentJSON.parse(
|
|
93
|
+
fromTemplateRepo,
|
|
94
|
+
) as commentJSON.CommentObject;
|
|
93
95
|
|
|
94
96
|
if (context.mergeArguments === "merge-current") {
|
|
95
97
|
// Performs Lodash Merge with current as the override
|
|
96
|
-
return
|
|
98
|
+
return commentJSON.stringify(
|
|
99
|
+
lodashMerge(fromTemplateJson, currentJson),
|
|
100
|
+
null,
|
|
101
|
+
inferJSONIndent(current),
|
|
102
|
+
);
|
|
97
103
|
}
|
|
98
104
|
|
|
99
105
|
if (context.mergeArguments === "merge-template") {
|
|
100
106
|
// Performs Lodash Merge with current as the override
|
|
101
|
-
return
|
|
107
|
+
return commentJSON.stringify(
|
|
108
|
+
lodashMerge(currentJson, fromTemplateJson),
|
|
109
|
+
null,
|
|
110
|
+
inferJSONIndent(current),
|
|
111
|
+
);
|
|
102
112
|
}
|
|
103
113
|
|
|
104
114
|
const { missingIsDelete, ignoreNewProperties, paths } =
|
|
105
115
|
context.mergeArguments as JsonPathOverrides;
|
|
106
116
|
|
|
107
|
-
const returnJson =
|
|
117
|
+
const returnJson = commentJSON.parse(current) as commentJSON.CommentObject;
|
|
108
118
|
paths.forEach((p) => {
|
|
109
119
|
const [jPath, overrideType] = p;
|
|
110
120
|
|
|
@@ -158,7 +168,7 @@ export async function merge(
|
|
|
158
168
|
});
|
|
159
169
|
}
|
|
160
170
|
|
|
161
|
-
return
|
|
171
|
+
return commentJSON.stringify(returnJson, null, inferJSONIndent(current));
|
|
162
172
|
}
|
|
163
173
|
|
|
164
174
|
/**
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { execSync } from "child_process";
|
|
2
|
+
import { gitCurrentRef } from "./git-current-ref";
|
|
3
|
+
|
|
4
|
+
describe("getCurrentRef", () => {
|
|
5
|
+
it("gets the current sha", async () => {
|
|
6
|
+
expect(
|
|
7
|
+
await gitCurrentRef({
|
|
8
|
+
rootDir: process.cwd(),
|
|
9
|
+
}),
|
|
10
|
+
).toEqual(execSync("git rev-parse HEAD").toString().trim());
|
|
11
|
+
});
|
|
12
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./git-current-ref";
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A function that operates within the root dir and returns the
|
|
3
|
+
* current ref for its state. This abstracts the idea of getting
|
|
4
|
+
* the current commit sha, so that things like other custom templating
|
|
5
|
+
* frameworks can provide their own ref
|
|
6
|
+
*/
|
|
7
|
+
export type TemplateRefDriverFn = (options: {
|
|
8
|
+
/** The root dir where we want to get the "current" ref */
|
|
9
|
+
rootDir: string;
|
|
10
|
+
}) => Promise<string>;
|
|
@@ -192,6 +192,127 @@ describe("templateSync", () => {
|
|
|
192
192
|
await fileMatchDownstream(tmpDir, "plugins/custom-plugin.js");
|
|
193
193
|
await fileMatchDownstream(tmpDir, "package.json");
|
|
194
194
|
});
|
|
195
|
+
it("updates the local templatesync with the current ref if updateAfterRef is true", async () => {
|
|
196
|
+
// Remove the local sync overrides
|
|
197
|
+
await rm(join(tmpDir, "templatesync.local.json"));
|
|
198
|
+
|
|
199
|
+
const mockLocalConfig = {
|
|
200
|
+
afterRef: "dummySha",
|
|
201
|
+
ignore: [
|
|
202
|
+
// We don't have a need for this in here, but it's an example of keeping things cleaner for our custom plugins
|
|
203
|
+
"plugins/**",
|
|
204
|
+
],
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
writeFileSync(
|
|
208
|
+
join(tmpDir, "templatesync.local.json"),
|
|
209
|
+
JSON.stringify(mockLocalConfig),
|
|
210
|
+
);
|
|
211
|
+
|
|
212
|
+
// We will only update the templated.ts
|
|
213
|
+
const mockDiffDriver = jest
|
|
214
|
+
.fn()
|
|
215
|
+
.mockImplementation(async () => ["src/templated.ts"]);
|
|
216
|
+
const mockCurrentRefDriver = jest
|
|
217
|
+
.fn()
|
|
218
|
+
.mockImplementation(async () => "newestSha");
|
|
219
|
+
const result = await templateSync({
|
|
220
|
+
tmpCloneDir: "stubbed-by-driver",
|
|
221
|
+
cloneDriver: dummyCloneDriver,
|
|
222
|
+
repoUrl: "not-important",
|
|
223
|
+
repoDir: tmpDir,
|
|
224
|
+
updateAfterRef: true,
|
|
225
|
+
diffDriver: mockDiffDriver,
|
|
226
|
+
currentRefDriver: mockCurrentRefDriver,
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
// since there was no override for this file, not changes from the local file
|
|
230
|
+
expect(result.localFileChanges).toEqual(expect.objectContaining({}));
|
|
231
|
+
|
|
232
|
+
// Verify the files
|
|
233
|
+
await fileMatchTemplate(tmpDir, "templatesync.json");
|
|
234
|
+
await fileMatchTemplate(tmpDir, "src/templated.ts");
|
|
235
|
+
|
|
236
|
+
// Expect the none of the diff files to work
|
|
237
|
+
await fileMatchDownstream(tmpDir, "src/index.ts");
|
|
238
|
+
await fileMatchDownstream(tmpDir, "plugins/custom-plugin.js");
|
|
239
|
+
await fileMatchDownstream(tmpDir, "package.json");
|
|
240
|
+
|
|
241
|
+
// Ensure we have updated the local template field
|
|
242
|
+
expect(
|
|
243
|
+
JSON.parse(
|
|
244
|
+
(await readFile(join(tmpDir, "templatesync.local.json"))).toString(),
|
|
245
|
+
),
|
|
246
|
+
).toEqual({
|
|
247
|
+
...mockLocalConfig,
|
|
248
|
+
afterRef: "newestSha",
|
|
249
|
+
});
|
|
250
|
+
});
|
|
251
|
+
it("creates the local templatesync with the current ref if updateAfterRef is true and no local template exists", async () => {
|
|
252
|
+
// Remove the local sync overrides
|
|
253
|
+
await rm(join(tmpDir, "templatesync.local.json"));
|
|
254
|
+
|
|
255
|
+
// We will only update the templated.ts
|
|
256
|
+
const mockDiffDriver = jest
|
|
257
|
+
.fn()
|
|
258
|
+
.mockImplementation(async () => ["src/templated.ts"]);
|
|
259
|
+
const mockCurrentRefDriver = jest
|
|
260
|
+
.fn()
|
|
261
|
+
.mockImplementation(async () => "newestSha");
|
|
262
|
+
const result = await templateSync({
|
|
263
|
+
tmpCloneDir: "stubbed-by-driver",
|
|
264
|
+
cloneDriver: dummyCloneDriver,
|
|
265
|
+
repoUrl: "not-important",
|
|
266
|
+
repoDir: tmpDir,
|
|
267
|
+
updateAfterRef: true,
|
|
268
|
+
diffDriver: mockDiffDriver,
|
|
269
|
+
currentRefDriver: mockCurrentRefDriver,
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
// since there was no override for this file, not changes from the local file
|
|
273
|
+
expect(result.localFileChanges).toEqual(expect.objectContaining({}));
|
|
274
|
+
|
|
275
|
+
// Verify the files
|
|
276
|
+
await fileMatchTemplate(tmpDir, "templatesync.json");
|
|
277
|
+
await fileMatchTemplate(tmpDir, "src/templated.ts");
|
|
278
|
+
const packageJson = JSON.parse(
|
|
279
|
+
readFileSync(resolve(tmpDir, "package.json")).toString(),
|
|
280
|
+
);
|
|
281
|
+
|
|
282
|
+
expect(packageJson).toEqual({
|
|
283
|
+
name: "mypkg",
|
|
284
|
+
description: "my description",
|
|
285
|
+
dependencies: {
|
|
286
|
+
mypackage: "^1.2.0",
|
|
287
|
+
newpacakge: "^22.2.2",
|
|
288
|
+
package2: "3.22.1",
|
|
289
|
+
huh: "~1.0.0",
|
|
290
|
+
},
|
|
291
|
+
engines: {
|
|
292
|
+
node: ">=15",
|
|
293
|
+
},
|
|
294
|
+
scripts: {
|
|
295
|
+
build: "build",
|
|
296
|
+
test: "jest",
|
|
297
|
+
myscript: "somescript",
|
|
298
|
+
},
|
|
299
|
+
// By default we add new top-level fields
|
|
300
|
+
version: "new-version",
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
// Expect the none of the diff files to work
|
|
304
|
+
await fileMatchDownstream(tmpDir, "src/index.ts");
|
|
305
|
+
await fileMatchDownstream(tmpDir, "plugins/custom-plugin.js");
|
|
306
|
+
|
|
307
|
+
// Ensure we have updated the local template field
|
|
308
|
+
expect(
|
|
309
|
+
JSON.parse(
|
|
310
|
+
(await readFile(join(tmpDir, "templatesync.local.json"))).toString(),
|
|
311
|
+
),
|
|
312
|
+
).toEqual({
|
|
313
|
+
afterRef: "newestSha",
|
|
314
|
+
});
|
|
315
|
+
});
|
|
195
316
|
});
|
|
196
317
|
|
|
197
318
|
// helper
|