@halospv3/hce.shared-config 2.6.4 → 3.0.0-develop.2
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 +356 -101
- package/README.md +100 -87
- package/dotnet/.github/workflows/_unit_test.yml +6 -3
- package/dotnet/.github/workflows/ci.yml +2 -2
- package/dotnet/.github/workflows/dotnet-release.yml +31 -28
- package/dotnet/.github/workflows/sample-dotnet-build.yml +16 -11
- package/dotnet/ExecNupkgDeterministicator.README.md +20 -0
- package/dotnet/ExecNupkgDeterministicator.targets +173 -0
- package/dotnet/GitVersion.yml +3 -1
- package/dotnet/GitVersion6.0.yml +3 -1
- package/dotnet/HCE.Shared.sln +34 -0
- package/dotnet/HCE.Shared.targets +1 -0
- package/dotnet/PublishAll.targets +2 -0
- package/dotnet/SignAfterPack.targets +104 -0
- package/dotnet/samples/HCE.Shared.DeterministicNupkg/Dummy.cs +6 -0
- package/dotnet/samples/HCE.Shared.DeterministicNupkg/HCE.Shared.DeterministicNupkg.csproj +21 -0
- package/dotnet/samples/HCE.Shared.SignAfterPack/Class1.cs +6 -0
- package/dotnet/samples/HCE.Shared.SignAfterPack/HCE.Shared.SignAfterPack.csproj +21 -0
- package/dotnet/samples/HCE.Shared.SignAfterPack/sampleCert.samplepfx +0 -0
- package/dotnet/samples/README.md +7 -0
- package/package.json +72 -73
- package/src/CaseInsensitiveMap.ts +34 -0
- package/src/commitlintConfig.ts +17 -9
- package/src/debug.ts +3 -3
- package/src/dotnet/GithubNugetRegistryInfo.ts +60 -0
- package/src/dotnet/GitlabNugetRegistryInfo.ts +112 -0
- package/src/dotnet/IsNextVersionAlreadyPublished.cli.ts +44 -0
- package/src/dotnet/MSBuildProject.ts +557 -76
- package/src/dotnet/MSBuildProjectProperties.ts +280 -15
- package/src/dotnet/NugetProjectProperties.ts +608 -0
- package/src/dotnet/NugetRegistryInfo.ts +939 -0
- package/src/dotnet/helpers.ts +448 -0
- package/src/eslintConfig.ts +174 -71
- package/src/index.ts +1 -3
- package/src/semantic-release__commit-analyzer.d.ts +44 -38
- package/src/semantic-release__exec.d.ts +15 -0
- package/src/semantic-release__git.d.ts +85 -88
- package/src/semantic-release__github.d.ts +139 -139
- package/src/semanticReleaseConfig.ts +106 -47
- package/src/semanticReleaseConfigDotnet.ts +394 -104
- package/src/setupGitPluginSpec.ts +149 -57
- package/src/tsconfig.json +8 -8
- package/src/utils/Exact.ts +49 -0
- package/src/utils/GracefulRecursion.d.ts +12 -0
- package/src/utils/env.ts +44 -0
- package/src/utils/execAsync.ts +77 -0
- package/src/utils/miscTypes.ts +17 -0
- package/src/utils/reflection/FunctionLike.d.ts +17 -0
- package/src/utils/reflection/GetterDescriptor.d.ts +8 -0
- package/src/utils/reflection/InstancePropertyDescriptorMap.d.ts +32 -0
- package/src/utils/reflection/InstanceTypeOrSelfPropertyDescriptorMap.d.ts +20 -0
- package/src/utils/reflection/OwnGetterDescriptorMap.d.ts +17 -0
- package/src/utils/reflection/OwnKeyOf.d.ts +20 -0
- package/src/utils/reflection/OwnPropertyDescriptorMap.d.ts +82 -0
- package/src/utils/reflection/PropertyDescriptorMap.d.ts +15 -0
- package/src/utils/reflection/filterForGetters.ts +59 -0
- package/src/utils/reflection/getOwnPropertyDescriptors.ts +52 -0
- package/src/utils/reflection/getOwnPropertyDescriptorsRecursively.ts +127 -0
- package/src/utils/reflection/getPrototypeChainOf.ts +85 -0
- package/src/utils/reflection/getPrototypeOf.ts +12 -0
- package/src/utils/reflection/inheritance.ts +262 -0
- package/src/utils/reflection/isConstructor.ts +74 -0
- package/src/utils/reflection/isGetterDescriptor.ts +11 -0
- package/src/utils/reflection/listOwnGetters.ts +80 -0
- package/src/utils/reflection.ts +18 -0
- package/cjs/commitlintConfig-wrapper.mjs +0 -6
- package/cjs/commitlintConfig.cjs +0 -14
- package/cjs/commitlintConfig.cjs.map +0 -1
- package/cjs/commitlintConfig.d.ts +0 -4
- package/cjs/commitlintConfig.d.ts.map +0 -1
- package/cjs/debug.cjs +0 -13
- package/cjs/debug.cjs.map +0 -1
- package/cjs/debug.d.ts +0 -4
- package/cjs/debug.d.ts.map +0 -1
- package/cjs/dotnet/MSBuildProject.cjs +0 -84
- package/cjs/dotnet/MSBuildProject.cjs.map +0 -1
- package/cjs/dotnet/MSBuildProject.d.ts +0 -42
- package/cjs/dotnet/MSBuildProject.d.ts.map +0 -1
- package/cjs/dotnet/MSBuildProjectProperties.cjs +0 -22
- package/cjs/dotnet/MSBuildProjectProperties.cjs.map +0 -1
- package/cjs/dotnet/MSBuildProjectProperties.d.ts +0 -13
- package/cjs/dotnet/MSBuildProjectProperties.d.ts.map +0 -1
- package/cjs/dotnet/createDummyNupkg.cjs +0 -26
- package/cjs/dotnet/createDummyNupkg.cjs.map +0 -1
- package/cjs/dotnet/createDummyNupkg.d.ts +0 -2
- package/cjs/dotnet/createDummyNupkg.d.ts.map +0 -1
- package/cjs/dotnet/dotnetGHPR.cjs +0 -173
- package/cjs/dotnet/dotnetGHPR.cjs.map +0 -1
- package/cjs/dotnet/dotnetGHPR.d.ts +0 -37
- package/cjs/dotnet/dotnetGHPR.d.ts.map +0 -1
- package/cjs/dotnet/dotnetGLPR.cjs +0 -41
- package/cjs/dotnet/dotnetGLPR.cjs.map +0 -1
- package/cjs/dotnet/dotnetGLPR.d.ts +0 -13
- package/cjs/dotnet/dotnetGLPR.d.ts.map +0 -1
- package/cjs/dotnet/dotnetHelpers.cjs +0 -141
- package/cjs/dotnet/dotnetHelpers.cjs.map +0 -1
- package/cjs/dotnet/dotnetHelpers.d.ts +0 -26
- package/cjs/dotnet/dotnetHelpers.d.ts.map +0 -1
- package/cjs/dotnet-wrapper.mjs +0 -6
- package/cjs/dotnet.cjs +0 -15
- package/cjs/dotnet.cjs.map +0 -1
- package/cjs/dotnet.d.ts +0 -7
- package/cjs/dotnet.d.ts.map +0 -1
- package/cjs/envUtils-wrapper.mjs +0 -6
- package/cjs/envUtils.cjs +0 -37
- package/cjs/envUtils.cjs.map +0 -1
- package/cjs/envUtils.d.ts +0 -15
- package/cjs/envUtils.d.ts.map +0 -1
- package/cjs/eslintConfig-wrapper.mjs +0 -6
- package/cjs/eslintConfig.cjs +0 -52
- package/cjs/eslintConfig.cjs.map +0 -1
- package/cjs/eslintConfig.d.ts +0 -3
- package/cjs/eslintConfig.d.ts.map +0 -1
- package/cjs/findStaticConfig-wrapper.mjs +0 -6
- package/cjs/findStaticConfig.cjs +0 -34
- package/cjs/findStaticConfig.cjs.map +0 -1
- package/cjs/findStaticConfig.d.ts +0 -2
- package/cjs/findStaticConfig.d.ts.map +0 -1
- package/cjs/index-wrapper.mjs +0 -6
- package/cjs/index.cjs +0 -10
- package/cjs/index.cjs.map +0 -1
- package/cjs/index.d.ts +0 -5
- package/cjs/index.d.ts.map +0 -1
- package/cjs/semantic-release__commit-analyzer.d.cjs +0 -2
- package/cjs/semantic-release__commit-analyzer.d.cjs.map +0 -1
- package/cjs/semantic-release__git.d.cjs +0 -2
- package/cjs/semantic-release__git.d.cjs.map +0 -1
- package/cjs/semantic-release__github.d.cjs +0 -2
- package/cjs/semantic-release__github.d.cjs.map +0 -1
- package/cjs/semanticReleaseConfig-wrapper.mjs +0 -6
- package/cjs/semanticReleaseConfig.cjs +0 -33
- package/cjs/semanticReleaseConfig.cjs.map +0 -1
- package/cjs/semanticReleaseConfig.d.ts +0 -4
- package/cjs/semanticReleaseConfig.d.ts.map +0 -1
- package/cjs/semanticReleaseConfigDotnet-wrapper.mjs +0 -7
- package/cjs/semanticReleaseConfigDotnet.cjs +0 -112
- package/cjs/semanticReleaseConfigDotnet.cjs.map +0 -1
- package/cjs/semanticReleaseConfigDotnet.d.ts +0 -51
- package/cjs/semanticReleaseConfigDotnet.d.ts.map +0 -1
- package/cjs/setupGitPluginSpec-wrapper.mjs +0 -6
- package/cjs/setupGitPluginSpec.cjs +0 -67
- package/cjs/setupGitPluginSpec.cjs.map +0 -1
- package/cjs/setupGitPluginSpec.d.ts +0 -19
- package/cjs/setupGitPluginSpec.d.ts.map +0 -1
- package/src/dotnet/createDummyNupkg.ts +0 -30
- package/src/dotnet/dotnetGHPR.ts +0 -232
- package/src/dotnet/dotnetGLPR.ts +0 -46
- package/src/dotnet/dotnetHelpers.ts +0 -184
- package/src/dotnet.ts +0 -6
- package/src/envUtils.ts +0 -36
- package/src/findStaticConfig.ts +0 -31
- package/static/.releaserc.yml +0 -35
|
@@ -1,75 +1,167 @@
|
|
|
1
1
|
import type { AssetEntry, Options as GitOptions } from '@semantic-release/git';
|
|
2
|
-
import type {
|
|
2
|
+
import type { PluginSpecSRGit, PluginSpecTuple } from './semanticReleaseConfig.js';
|
|
3
3
|
|
|
4
4
|
export const GitPluginId = '@semantic-release/git';
|
|
5
|
-
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* As specified at https://github.com/semantic-release/git#options
|
|
8
|
+
* To use, assign or create an object with the same (but mutable) properties and deeply-copy to the object
|
|
9
|
+
* @satisfies { GitOptions }
|
|
10
|
+
*/
|
|
6
11
|
export const DefaultOptions = {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
12
|
+
assets: [
|
|
13
|
+
'README.md',
|
|
14
|
+
'CHANGELOG.md',
|
|
15
|
+
'package.json',
|
|
16
|
+
'package-lock.json',
|
|
17
|
+
'npm-shrinkwrap.json',
|
|
18
|
+
],
|
|
19
|
+
message:
|
|
20
|
+
'chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}',
|
|
21
|
+
} as const satisfies GitOptions;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Check if {@link unk} is an {@link AssetEntry}.
|
|
25
|
+
* @param unk Anything.
|
|
26
|
+
* @returns `true` if {@link unk} is an {@link AssetEntry}. Else, `false`.
|
|
27
|
+
*/
|
|
28
|
+
function isGitAsset(unk: unknown): unk is AssetEntry {
|
|
29
|
+
if (typeof unk === 'string')
|
|
30
|
+
return true;
|
|
31
|
+
// Avoid ending condition with `typeof unk.path === 'string'`.
|
|
32
|
+
// TS narrowing is bugged; requires the check to be performed TWICE!!
|
|
33
|
+
if (typeof unk === 'object' && unk != undefined && 'path' in unk) {
|
|
34
|
+
return typeof unk.path === 'string';
|
|
35
|
+
}
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Convert one or more {@link AssetEntry AssetEntries} to a `string[]`.
|
|
41
|
+
* @param assets The `assets` property of a {@link GitOptions} object. This may not be `false`.
|
|
42
|
+
* @returns A `string[]` of the given {@link AssetEntry} objects or strings.
|
|
43
|
+
*/
|
|
44
|
+
function gitAssetsToStringArray(
|
|
45
|
+
assets: Exclude<GitOptions['assets'], false>,
|
|
46
|
+
): string[] {
|
|
47
|
+
if (assets === undefined)
|
|
48
|
+
return [];
|
|
49
|
+
if (Array.isArray(assets)) {
|
|
50
|
+
return assets.filter(asset => isGitAsset(asset))
|
|
51
|
+
.map(v => typeof v === 'string' ? v : v.path);
|
|
52
|
+
}
|
|
53
|
+
if (typeof assets === 'string')
|
|
54
|
+
return [assets] as string[];
|
|
55
|
+
if (typeof assets.path === 'string')
|
|
56
|
+
return [assets.path];
|
|
57
|
+
else
|
|
58
|
+
throw new TypeError('assets is not typeof GitOptions[\'assets\'!');
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Sanitize a {@link GitOptions} object so its {@link GitOptions#assets} property is either `false` or a `string[]`.
|
|
63
|
+
* @param opts A {@link GitOptions} object.
|
|
64
|
+
* @returns A {@link GitOptions} object whose {@link GitOptions#assets} is `string[] | false`.
|
|
65
|
+
*/
|
|
66
|
+
function sanitizeGitOptions(opts: GitOptions): Omit<GitOptions, 'assets'> & { assets: string[] | false } {
|
|
67
|
+
return { ...opts, assets: opts.assets === false ? opts.assets : gitAssetsToStringArray(opts.assets) };
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
*Determine if {@link opts} is a {@link GitOptions} object.
|
|
72
|
+
* @param opts Anything.
|
|
73
|
+
* @returns `true` if {@link opts} is a {@link GitOptions} object. Else, `false`.
|
|
74
|
+
*/
|
|
75
|
+
function isGitOptions(opts: unknown): opts is GitOptions {
|
|
76
|
+
let isOptions = false;
|
|
77
|
+
|
|
78
|
+
if (typeof opts !== 'object' || opts == undefined)
|
|
79
|
+
return isOptions;
|
|
80
|
+
if ('assets' in opts) {
|
|
81
|
+
isOptions = Array.isArray(opts.assets)
|
|
82
|
+
? opts.assets.every(unk => isGitAsset(unk))
|
|
83
|
+
: isGitAsset(opts.assets);
|
|
84
|
+
}
|
|
85
|
+
if ('message' in opts)
|
|
86
|
+
isOptions = typeof opts.message === 'string';
|
|
87
|
+
return isOptions;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Determine if {@link pluginSpec} includes a {@link GitOptions} object.
|
|
92
|
+
* @param pluginSpec a {@link PluginSpecTuple}.
|
|
93
|
+
* @returns `true` if {@link pluginSpec[1]} is a {@link GitOptions} object. Else, `false`.
|
|
94
|
+
*/
|
|
95
|
+
function hasGitOptions<P extends string>(pluginSpec: PluginSpecTuple<P>): pluginSpec is PluginSpecTuple<P, GitOptions> {
|
|
96
|
+
return isGitOptions(pluginSpec[1]);
|
|
97
|
+
};
|
|
10
98
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
99
|
+
/**
|
|
100
|
+
* Determined if the plugin ID in {@link pluginSpec} is {@link GitPluginId}.
|
|
101
|
+
* @param pluginSpec A {@link PluginSpecTuple}
|
|
102
|
+
* @returns `true` if {@link pluginSpec[0]} is {@link GitPluginId}
|
|
103
|
+
*/
|
|
104
|
+
function isGitPluginSpecTuple<T>(pluginSpec: [string, T]): pluginSpec is [typeof GitPluginId, T] {
|
|
105
|
+
return pluginSpec[0] === GitPluginId;
|
|
16
106
|
}
|
|
17
107
|
|
|
18
108
|
/**
|
|
19
109
|
* https://github.com/semantic-release/git#options
|
|
20
110
|
*
|
|
21
111
|
* This plugin may be deprecated at a later date.
|
|
22
|
-
* Why
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
* @returns A {@link
|
|
26
|
-
* todo: deprecate for generic or parameterized function
|
|
112
|
+
* Q: Why would I need to commit during release?
|
|
113
|
+
* A: This is for committing your changelog, README, and/or other files updated during the release procedure.
|
|
114
|
+
* @param plugins An ordered array of {@link PluginSpecTuple PluginSpecTuples}.
|
|
115
|
+
* @returns A {@link PluginSpecTuple}[]. Duplicate `@semantic-release/git` plugin entries are merged or overridden. The last entry takes priority e.g. if the last entry is `{assets: false}`, previous entries' assets are ignored.
|
|
27
116
|
*/
|
|
28
|
-
export function setupGitPluginSpec(plugins:
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
if (pluginSpec === GitPluginId || pluginSpec[0] === GitPluginId) {
|
|
34
|
-
gitPluginIndex = pluginSpecIndex;
|
|
35
|
-
return true;
|
|
36
|
-
}
|
|
37
|
-
return false;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// if Git plugin not in load order, return as-is.
|
|
41
|
-
if (!newPlugins.some(pluginSpecIsGit)) return plugins;
|
|
117
|
+
export function setupGitPluginSpec(plugins: PluginSpecTuple[]): PluginSpecTuple[] {
|
|
118
|
+
/** if Git plugin not in load order, return as-is. */
|
|
119
|
+
const firstGitPluginIndex = plugins.findIndex(plugin => isGitPluginSpecTuple(plugin));
|
|
120
|
+
if (firstGitPluginIndex === -1)
|
|
121
|
+
return plugins;
|
|
42
122
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
123
|
+
/**
|
|
124
|
+
* the following two const variables are references--not clones.
|
|
125
|
+
* Modifying them will affect the plugins array.
|
|
126
|
+
*/
|
|
127
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
128
|
+
const firstGitPlugin = plugins[firstGitPluginIndex]!;
|
|
129
|
+
const firstGitOpts: ReturnType<typeof sanitizeGitOptions> = isGitOptions(firstGitPlugin[1])
|
|
130
|
+
? sanitizeGitOptions(firstGitPlugin[1])
|
|
131
|
+
: DefaultOptions;
|
|
47
132
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
133
|
+
/**
|
|
134
|
+
* remove duplicate Git plugin entries;
|
|
135
|
+
* merge extra options into firstGitPlugin's options
|
|
136
|
+
* if `firstGitOpts.assets === false`, do not change it.
|
|
137
|
+
* All duplicate PluginSpecSRGit entries are then reassigned `undefined` and all
|
|
138
|
+
* `undefined` items are filtered from the plugins array.
|
|
139
|
+
*/
|
|
140
|
+
return plugins.map((current: PluginSpecTuple, index): PluginSpecTuple | PluginSpecSRGit | undefined => {
|
|
141
|
+
// skip everything up to and including the first Git PluginSpec
|
|
142
|
+
if (index <= firstGitPluginIndex || !isGitPluginSpecTuple(current))
|
|
143
|
+
return current;
|
|
52
144
|
|
|
53
|
-
|
|
145
|
+
/** if another Git PluginSpec is discovered, copy its options to the first Git PluginSpec and return undefined. */
|
|
146
|
+
if (hasGitOptions(current)) {
|
|
147
|
+
const currentGitOpts = sanitizeGitOptions(current[1]);
|
|
54
148
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
discardPile.push(i);
|
|
68
|
-
}
|
|
69
|
-
});
|
|
70
|
-
for (const i of discardPile.sort().reverse()) {
|
|
71
|
-
newPlugins.splice(i, 1);
|
|
72
|
-
}
|
|
149
|
+
if (currentGitOpts.assets === false) {
|
|
150
|
+
firstGitOpts.assets = false;
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
const assets: string[] = gitAssetsToStringArray(currentGitOpts.assets);
|
|
154
|
+
if (Array.isArray(firstGitOpts.assets)) {
|
|
155
|
+
firstGitOpts.assets.push(...assets);
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
firstGitOpts.assets = assets;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
73
161
|
|
|
74
|
-
|
|
162
|
+
if (typeof currentGitOpts.message === 'string')
|
|
163
|
+
firstGitOpts.message = currentGitOpts.message;
|
|
164
|
+
}
|
|
165
|
+
return undefined;
|
|
166
|
+
}).filter(pluginSpec => pluginSpec !== undefined);
|
|
75
167
|
}
|
package/src/tsconfig.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
2
|
+
"extends": "../tsconfig.base.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"outDir": "../_tsout/src",
|
|
5
|
+
"isolatedDeclarations": false
|
|
6
|
+
},
|
|
7
|
+
"include": [
|
|
8
|
+
"./**/*"
|
|
9
|
+
]
|
|
10
10
|
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ### `Exact<T, S>`
|
|
3
|
+
*
|
|
4
|
+
* [issue](https://github.com/microsoft/TypeScript/issues/12936#issuecomment-2816928183)\
|
|
5
|
+
* [author](https://github.com/ahrjarrett)\
|
|
6
|
+
* license: unlicensed[!]
|
|
7
|
+
* @see
|
|
8
|
+
* - {@link https://tsplay.dev/NnGG6m}
|
|
9
|
+
*/
|
|
10
|
+
export type Exact<T, S> = [keyof T] extends [keyof S]
|
|
11
|
+
? [T] extends [S] ? { [K in keyof T]: T[K] } : S
|
|
12
|
+
: { [K in keyof T as K extends keyof S ? never : K]: TypeError<`Excess: '${Coerce<K>}'`> };
|
|
13
|
+
|
|
14
|
+
// eslint-disable-next-line jsdoc/require-jsdoc, @typescript-eslint/no-unused-vars
|
|
15
|
+
function exact<S, T extends Exact<T, S>>(x: S, _y: T): T {
|
|
16
|
+
return x as unknown as T;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
// should succeed
|
|
20
|
+
exact({ a: 1 }, { a: 1 });
|
|
21
|
+
exact({ a: 1, b: 'two' }, { a: 1, b: 'two' });
|
|
22
|
+
|
|
23
|
+
// should raise a TypeError
|
|
24
|
+
try {
|
|
25
|
+
// @ts-expect-error Type 'boolean' is not assignable to type 'TypeError<"Excess: 'c'">'.ts(2322)
|
|
26
|
+
exact({ a: 1 }, { a: 1, b: 'two', c: false });
|
|
27
|
+
}
|
|
28
|
+
catch { /* empty */ }
|
|
29
|
+
try {
|
|
30
|
+
// @ts-expect-error Type 'number' is not assignable to type 'TypeError<"Excess: 'c'">'.ts(2322)
|
|
31
|
+
exact({ a: 1, b: 2 }, { a: 1, b: 2, c: 3 });
|
|
32
|
+
}
|
|
33
|
+
catch { /* empty */ }
|
|
34
|
+
try {
|
|
35
|
+
// @ts-expect-error Argument of type '{ a: number; }' is not assignable to parameter of type '{ a: number; b: number; }'. Property 'b' is missing in type '{ a: number; }' but required in type '{ a: number; b: number; }'.ts(2345)
|
|
36
|
+
exact({ a: 1, b: 2 }, { a: 1 });
|
|
37
|
+
}
|
|
38
|
+
catch { /* empty */ }
|
|
39
|
+
interface TypeError<Message> { [' TypeError']: Message }
|
|
40
|
+
// prior art: use arktype's ^^^ leading whitespace trick to avoid collisions
|
|
41
|
+
|
|
42
|
+
type Coerce<T> = `${T & (string | number)}`;
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
// @ts-expect-error Should error
|
|
46
|
+
exact({ a: 1 }, { a: 1, b: 2 });
|
|
47
|
+
// ^ 🚫 raises a TypeError here
|
|
48
|
+
}
|
|
49
|
+
catch { /* empty */ }
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// #region https://dev.to/adrien2p/mastering-recursive-types-in-typescript-handling-depth-limitations-gracefully-5f4o#a-more-robust-solution-tuplebased-increment-and-decrement-types
|
|
2
|
+
export type Length<T extends unknown[]> = (T extends { length: number } ? T['length'] : never) & number;
|
|
3
|
+
export type TupleOf<N extends number, T extends unknown[] = []> = Length<T> extends N
|
|
4
|
+
? T
|
|
5
|
+
: TupleOf<N, [...T, unknown]>;
|
|
6
|
+
export type Pop<T extends unknown[]> = T extends [...infer U, unknown] ? U : never;
|
|
7
|
+
// Increment adds an element to a tuple, effectively creating N + 1
|
|
8
|
+
export type Increment<N extends number> = Length<[1, ...TupleOf<N>]>;
|
|
9
|
+
// Decrement removes an element from a tuple, effectively creating N - 1
|
|
10
|
+
export type Decrement<N extends number> = Length<Pop<TupleOf<N>>>;
|
|
11
|
+
|
|
12
|
+
// #endregion https://dev.to/adrien2p/mastering-recursive-types-in-typescript-handling-depth-limitations-gracefully-5f4o#a-more-robust-solution-tuplebased-increment-and-decrement-types
|
package/src/utils/env.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { get,
|
|
2
|
+
config as loadDotenv,
|
|
3
|
+
type DotenvConfigOptions,
|
|
4
|
+
type GetOptions,
|
|
5
|
+
} from '@dotenvx/dotenvx';
|
|
6
|
+
import { env } from 'node:process';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* A thin wrapper for {@link loadDotenv}. Loads a .env file from {@link process.cwd()} with the given options (or defaults), returns the new value of {@link process.env} with optional overrides.
|
|
10
|
+
* @param [dotenvOptions] An optional {@link DotenvConfigOptions} object to pass to {@link loadDotenv}.
|
|
11
|
+
* @param [overrides] If provided, this {@link NodeJS.ProcessEnv} object is merged into the return value, overriding existing properties where overlap occurs.
|
|
12
|
+
* @returns A {@link NodeJS.ProcessEnv} object whose properties are variables loaded from the
|
|
13
|
+
* process environment, the nearest .env file, and {@link overrides} (if provided). Where
|
|
14
|
+
* overlap occurs, the later source takes priority.
|
|
15
|
+
*/
|
|
16
|
+
export function getEnv(dotenvOptions?: DotenvConfigOptions, overrides?: NodeJS.ProcessEnv): NodeJS.ProcessEnv {
|
|
17
|
+
loadDotenv(dotenvOptions);
|
|
18
|
+
|
|
19
|
+
if (overrides)
|
|
20
|
+
Object.assign(env, overrides);
|
|
21
|
+
|
|
22
|
+
return env;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Get the value from the given env var in the current process or nearby .env file.
|
|
27
|
+
* If found in process environment, its value is returned.
|
|
28
|
+
* Else, try to get it from the nearest .env file.
|
|
29
|
+
* If NOT found, return `undefined`
|
|
30
|
+
* @param envVar The environment variable to lookup.
|
|
31
|
+
* @param [options] Options to pass to {@link get}
|
|
32
|
+
* @returns The string value of the environment variable or `undefined`.
|
|
33
|
+
* `undefined` may be returned when the variable is undefined or its string is
|
|
34
|
+
* empty, whitespace, or appears to have been converted from `null` or
|
|
35
|
+
* `undefined`.
|
|
36
|
+
*/
|
|
37
|
+
export function getEnvVarValue(envVar: string, options?: GetOptions): string | undefined {
|
|
38
|
+
options ??= { ignore: ['MISSING_KEY', 'MISSING_ENV_FILE'] };
|
|
39
|
+
const value = String(env[envVar] ?? get(envVar, options)).trim();
|
|
40
|
+
// I hate this. Why is undefined converted to a string?
|
|
41
|
+
return value === '' || value === 'undefined'
|
|
42
|
+
? undefined
|
|
43
|
+
: value;
|
|
44
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/* eslint-disable jsdoc/no-defaults */
|
|
2
|
+
import { type } from 'arktype';
|
|
3
|
+
import { exec } from 'node:child_process';
|
|
4
|
+
import { constants } from 'node:os';
|
|
5
|
+
import { promisify } from 'node:util';
|
|
6
|
+
import { isNativeError } from 'node:util/types';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* A `promisify(exec)` wrapper to optionally assign the child process's STDERR as the {@link Error.prototype.cause}.
|
|
10
|
+
* @see {@link promisify}, {@link exec}
|
|
11
|
+
* @param command The command to run, with space-separated arguments.
|
|
12
|
+
* @param [setStderrAsCause=false] If true and the child process's stderr is available, the thrown Error's {@link Error.prototype.cause} is assigned the stderr string.
|
|
13
|
+
* @returns A promise of the child process's STDOUT and STDERR streams as strings
|
|
14
|
+
* @throws {Error | ChildProcessSpawnException}
|
|
15
|
+
*/
|
|
16
|
+
export async function execAsync(command: string, setStderrAsCause = false): Promise<{
|
|
17
|
+
stdout: string;
|
|
18
|
+
stderr: string;
|
|
19
|
+
}> {
|
|
20
|
+
return await promisify(exec)(command).catch((error: unknown): never => {
|
|
21
|
+
if (!isNativeError(error))
|
|
22
|
+
throw new Error(JSON.stringify(error));
|
|
23
|
+
|
|
24
|
+
if (setStderrAsCause && 'stderr' in error && typeof error.stderr === 'string' && error.stderr !== '')
|
|
25
|
+
error.cause ??= error.stderr;
|
|
26
|
+
|
|
27
|
+
if ('stdout' in error && typeof error.stdout === 'string') {
|
|
28
|
+
error.message
|
|
29
|
+
+= '\nSTDOUT:\n'
|
|
30
|
+
+ ` ${error.stdout.replaceAll('\n', '\n ')}`;
|
|
31
|
+
}
|
|
32
|
+
if ('stderr' in error && typeof error.stderr === 'string') {
|
|
33
|
+
error.message
|
|
34
|
+
+= '\nSTDERR:\n'
|
|
35
|
+
+ ` ${error.stderr.replaceAll('\n', '\n ')}`;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
throw new ChildProcessSpawnException(error.message, error);
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const T_ExecException = type('Error').and({
|
|
43
|
+
'cmd?': 'string | null',
|
|
44
|
+
'killed?': 'boolean | null',
|
|
45
|
+
'code?': 'number | null',
|
|
46
|
+
'signal?': type.null.or((Object.keys(constants.signals) as NodeJS.Signals[])
|
|
47
|
+
.map(v => type(`'${v}'`))
|
|
48
|
+
// eslint-disable-next-line unicorn/no-array-reduce
|
|
49
|
+
.reduce((previous, current) => previous.or(current))),
|
|
50
|
+
'stdout?': 'string',
|
|
51
|
+
'stderr?': 'string',
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
type _ExecException = typeof T_ExecException.inferOut;
|
|
55
|
+
|
|
56
|
+
export class ChildProcessSpawnException extends Error implements _ExecException {
|
|
57
|
+
constructor(
|
|
58
|
+
message: Parameters<typeof Error>[0],
|
|
59
|
+
options: typeof T_ExecException.inferIn,
|
|
60
|
+
) {
|
|
61
|
+
options = T_ExecException.from(options);
|
|
62
|
+
super(message, options);
|
|
63
|
+
this.cmd = options.cmd;
|
|
64
|
+
this.code = options.code;
|
|
65
|
+
this.killed = options.killed;
|
|
66
|
+
this.signal = options.signal;
|
|
67
|
+
this.stderr = options.stderr;
|
|
68
|
+
this.stdout = options.stdout;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
cmd: typeof T_ExecException.inferOut.cmd;
|
|
72
|
+
code: typeof T_ExecException.inferOut.code;
|
|
73
|
+
killed: typeof T_ExecException.inferOut.killed;
|
|
74
|
+
signal: typeof T_ExecException.inferOut.signal;
|
|
75
|
+
stderr: typeof T_ExecException.inferOut.stderr;
|
|
76
|
+
stdout: typeof T_ExecException.inferOut.stdout;
|
|
77
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type } from 'arktype';
|
|
2
|
+
|
|
3
|
+
export const tBooleanString = type('"true" | "false"');
|
|
4
|
+
export type BooleanString = typeof tBooleanString.infer;
|
|
5
|
+
|
|
6
|
+
export const tEmptyOrBooleanString = type(tBooleanString.or('""'));
|
|
7
|
+
export type EmptyOrBooleanString = typeof tEmptyOrBooleanString.infer;
|
|
8
|
+
|
|
9
|
+
export type Integer<N extends number> = `${N}` extends `${number}.${number}` ? never : N;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @see https://stackoverflow.com/a/73920140/14894786
|
|
13
|
+
*/
|
|
14
|
+
export type TupleIndices<T extends readonly unknown[]>
|
|
15
|
+
= Extract<keyof T, `${number}`> extends `${infer N extends number}` ? N : never;
|
|
16
|
+
|
|
17
|
+
export type InstanceOrStatic = 'Instance' | 'Static';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
/**
|
|
3
|
+
* A generic alternative to the boxing {@link Function} type. Based on the
|
|
4
|
+
* expressions of {@link Parameters} and {@link ReturnType}.
|
|
5
|
+
* @template [T=((...args: any[] | readonly any[]) => any)] Any function-like type.
|
|
6
|
+
* @template [P=Parameters<T>]
|
|
7
|
+
* [INTERNAL] The parameters of {@link T}.
|
|
8
|
+
* @template [R=ReturnType<T>]
|
|
9
|
+
* [INTERNAL] The return type of {@link T}.
|
|
10
|
+
* @default ((...args: any[] | readonly any[]) => any)
|
|
11
|
+
* @since 3.0.0
|
|
12
|
+
*/
|
|
13
|
+
export type FunctionLike<
|
|
14
|
+
T extends ((...args: any[] | readonly any[]) => any) = ((...args: any[] | readonly any[]) => any),
|
|
15
|
+
P extends Parameters<T> = Parameters<T>,
|
|
16
|
+
R extends ReturnType<T> = ReturnType<T>,
|
|
17
|
+
> = T & ((...args: P) => R);
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A type for casting a property descriptor to a getter descriptor.\
|
|
3
|
+
* Cast to this only after checking `typeof propertyDescriptor.get === 'function`
|
|
4
|
+
* @template [T=unknown] The type of the property.
|
|
5
|
+
* @since 4.0.0
|
|
6
|
+
*/
|
|
7
|
+
export type GetterDescriptor<T = unknown> = Omit<TypedPropertyDescriptor<T>, 'get'>
|
|
8
|
+
& Required<Pick<TypedPropertyDescriptor<T>, 'get'>>;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { PropertyDescriptorMap } from './PropertyDescriptorMap.ts';
|
|
2
|
+
import type {
|
|
3
|
+
BaseClassProto,
|
|
4
|
+
ConstructorConstraint,
|
|
5
|
+
InstanceTypeOrSelf,
|
|
6
|
+
SuperClassLike,
|
|
7
|
+
WithProto,
|
|
8
|
+
} from './inheritance.ts';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Generically-typed return type of `Object.GetOwnPropertyDescriptors` for class
|
|
12
|
+
* instances.
|
|
13
|
+
*
|
|
14
|
+
* Allows for statically-inferred property keys and values.
|
|
15
|
+
*
|
|
16
|
+
* Classes' `public` members are returned, including instance Getters and
|
|
17
|
+
* Setters.
|
|
18
|
+
* @template Class
|
|
19
|
+
* Any class type with its `[[Prototype]]` attached via a type-only `__proto__` property.
|
|
20
|
+
* The type of `__proto__` must extend {@link SuperClassLike} or {@link BaseClassProto}.
|
|
21
|
+
* @example
|
|
22
|
+
* ```ts
|
|
23
|
+
* const { NugetProjectProperties: NPP } = await import('../dotnet/NugetProjectProperties.js');
|
|
24
|
+
* const _instanceMembers: InstancePropertyDescriptorMap<typeof NPP> = Object.getOwnPropertyDescriptors(new NugetProjectProperties('',new CaseInsensitiveMap([['','']])));
|
|
25
|
+
* ```
|
|
26
|
+
* @since 3.0.0
|
|
27
|
+
*/
|
|
28
|
+
export type InstancePropertyDescriptorMap<
|
|
29
|
+
Class extends ConstructorConstraint<Class> & WithProto<SuperClassLike | BaseClassProto>,
|
|
30
|
+
> = Class['__proto__'] extends BaseClassProto
|
|
31
|
+
? PropertyDescriptorMap<InstanceType<Class>>
|
|
32
|
+
: PropertyDescriptorMap<InstanceType<Class>, InstanceTypeOrSelf<Class['__proto__']>>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { BaseClassProto, ConstructorLike, InstanceTypeOrSelf, ProtoOrSuperClass, SuperClassLike, WithProto } from './inheritance.ts';
|
|
2
|
+
import type { InstancePropertyDescriptorMap } from './InstancePropertyDescriptorMap.ts';
|
|
3
|
+
import type { PropertyDescriptorMap } from './PropertyDescriptorMap.ts';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Variant of {@link InstancePropertyDescriptorMap} with a lesser constraint on {@link T}.
|
|
7
|
+
* If {@link T} and/or {@link __proto__} are instantiable, the resulting
|
|
8
|
+
* property descriptor maps will be of the instances' types.
|
|
9
|
+
* @template T `null` or an `object`-like type.
|
|
10
|
+
* @template __proto__ The `[[Prototype]]` of {@link T}.
|
|
11
|
+
* @since 3.0.0
|
|
12
|
+
*/
|
|
13
|
+
export type InstanceTypeOrSelfPropertyDescriptorMap<
|
|
14
|
+
T extends object | null,
|
|
15
|
+
__proto__ extends ProtoOrSuperClass,
|
|
16
|
+
> = T extends ConstructorLike<T>
|
|
17
|
+
? __proto__ extends SuperClassLike | BaseClassProto
|
|
18
|
+
? InstancePropertyDescriptorMap<T & WithProto<__proto__>>
|
|
19
|
+
: PropertyDescriptorMap<InstanceType<T>, InstanceTypeOrSelf<__proto__>>
|
|
20
|
+
: PropertyDescriptorMap<InstanceTypeOrSelf<T>, InstanceTypeOrSelf<__proto__>>;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { GetterDescriptor } from './GetterDescriptor.ts';
|
|
2
|
+
import type { OwnKeyOf } from './OwnKeyOf.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* # !WARNING!
|
|
6
|
+
* > This does _not_ filter out non-getter properties! ALL properties are treated as getters. Because `get` is optional and present on all property descriptors, this type should only be used to cast properties for which `typeof p.get === 'function'`.
|
|
7
|
+
*
|
|
8
|
+
* A {@link GetterDescriptorMap} variant for omitting keys inherited from {@link __proto__}.
|
|
9
|
+
* Note: If `T` is `InstanceOf<class>`, then `__proto__` must be `InstanceTypeOrSelf<__proto__>`
|
|
10
|
+
* @template T The type the descriptor map describes.
|
|
11
|
+
* @template __proto__ The `[[Prototype]]` of {@link T}. Keys of {@link __proto__} are omitted from the descriptor map type.
|
|
12
|
+
* @since 3.0.0
|
|
13
|
+
*/
|
|
14
|
+
export type OwnGetterDescriptorMap<
|
|
15
|
+
T,
|
|
16
|
+
__proto__ extends object | null,
|
|
17
|
+
> = { [P in OwnKeyOf<T, __proto__>]: GetterDescriptor<T[P]> };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `keyof` type {@link T} excluding any keys of type {@link __proto__}
|
|
3
|
+
* @template T
|
|
4
|
+
* @template __proto__ `null` or any `object`-like type.
|
|
5
|
+
* @example
|
|
6
|
+
* OwnKeyOf<NPP, MSBPP> === "IsPackable" | "SuppressDependenciesWhenPacking" | "PackageVersion" | "PackageId" | "PackageDescription" | "Authors" | "Copyright" | "PackageRequireLicenseAcceptance" | "DevelopmentDependency" | "PackageLicenseExpression" | "PackageLicenseFile" | "PackageProjectUrl" | "PackageIcon" | "PackageReleaseNotes" | "PackageReadmeFile" | "PackageTags" | "PackageOutputPath" | "IncludeSymbols" | "IncludeSource" | "PackageType" | "IsTool" | "RepositoryUrl" | "RepositoryType" | "RepositoryCommit" | "SymbolPackageFormat" | "NoPackageAnalysis" | "MinClientVersion" | "IncludeBuildOutput" | "IncludeContentInPack" | "BuildOutputTargetFolder" | "ContentTargetFolders" | "NuspecFile" | "NuspecBasePath" | "NuspecProperties" | "Title" | "Company" | "Product"
|
|
7
|
+
* OwnKeyOf<typeof NPP, typeof MSBPP> === never ; // class NPP does not have non-inherited static members
|
|
8
|
+
* OwnKeyOf<typeof NPP, null> === "prototype" | "GetFullPath"
|
|
9
|
+
* @since 3.0.0
|
|
10
|
+
*/
|
|
11
|
+
export type OwnKeyOf<T, __proto__ extends object | null>
|
|
12
|
+
= Exclude<
|
|
13
|
+
__proto__ extends null
|
|
14
|
+
? keyof T
|
|
15
|
+
: Exclude<
|
|
16
|
+
keyof T,
|
|
17
|
+
keyof __proto__
|
|
18
|
+
>,
|
|
19
|
+
'__proto__'
|
|
20
|
+
>;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
BaseClass,
|
|
3
|
+
ClassLike,
|
|
4
|
+
ClassLike_Unknown,
|
|
5
|
+
ProtoOrSuperClass,
|
|
6
|
+
WithProto,
|
|
7
|
+
} from './inheritance.ts';
|
|
8
|
+
|
|
9
|
+
// todo: Omit [P in keyof T] where T['__proto__'][P] === T[P].
|
|
10
|
+
// todo: NEVER omit overridden class members! Does TypeScript expose that override in accessible metadata?
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* A typed {@link PropertyDescriptorMap} without any keys found in its `[[Prototype]]` chain.
|
|
14
|
+
* This may mean overridden class properties are wrongly omitted.
|
|
15
|
+
* @template T Any type with its `[[Prototype]]` attached via a type-only `__proto__` property. The type of `__proto__` must extends {@link ProtoOrSuperClass}.
|
|
16
|
+
* @since 3.0.0
|
|
17
|
+
*/
|
|
18
|
+
export type OwnPropertyDescriptorMap<T extends WithProto<ProtoOrSuperClass>>
|
|
19
|
+
= T['__proto__'] extends null
|
|
20
|
+
? { [P0 in keyof T]: TypedPropertyDescriptor<T[P0]>; }
|
|
21
|
+
: Omit<
|
|
22
|
+
{ [P0 in keyof T]: TypedPropertyDescriptor<T[P0]>; },
|
|
23
|
+
Exclude<
|
|
24
|
+
keyof { [P1 in keyof T['__proto__']]: TypedPropertyDescriptor<T['__proto__'][P1]> },
|
|
25
|
+
keyof ClassLike<BaseClass<ClassLike_Unknown>>
|
|
26
|
+
>
|
|
27
|
+
>;
|
|
28
|
+
|
|
29
|
+
// // todo: use SharedKeys to only keys where SharedKeys<T> in keyof T
|
|
30
|
+
// // eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
31
|
+
// type SharedKeys<T extends WithProto<ProtoOrSuperClass>> = Extract<keyof T, keyof T['__proto__']>;
|
|
32
|
+
|
|
33
|
+
// // todo: make this useful. The ReturnType is incorrect
|
|
34
|
+
// // eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
35
|
+
// declare function removeMatchingPropertyDescriptors<T0, T1>(
|
|
36
|
+
// a: { [P0 in keyof T0]: TypedPropertyDescriptor<T0[P0]> },
|
|
37
|
+
// b: { [P1 in keyof T1]: TypedPropertyDescriptor<T1[P1]> }
|
|
38
|
+
// ): Omit<typeof a, keyof (T0 & T1)>;
|
|
39
|
+
|
|
40
|
+
// /**
|
|
41
|
+
// * @see https://stackoverflow.com/a/56874389/1489478
|
|
42
|
+
// * @example
|
|
43
|
+
// * ```ts
|
|
44
|
+
// * interface MyInterface {
|
|
45
|
+
// * a: number;
|
|
46
|
+
// * b: string;
|
|
47
|
+
// * c: number;
|
|
48
|
+
// * }
|
|
49
|
+
// * type MyType = KeysMatching<MyInterface, number>;
|
|
50
|
+
// * type MyType = "a" | "c";
|
|
51
|
+
// * @todo KeysMatching
|
|
52
|
+
// */
|
|
53
|
+
// // eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
54
|
+
// type KeysMatching<T extends object, V> = {
|
|
55
|
+
// [K in keyof T]-?: T[K] extends V ? K : never
|
|
56
|
+
// }[keyof T];
|
|
57
|
+
|
|
58
|
+
// /**
|
|
59
|
+
// * @todo KeysNotMatching
|
|
60
|
+
// */
|
|
61
|
+
// // eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
62
|
+
// type KeysNotMatching<T extends object, V> = {
|
|
63
|
+
// [K in keyof T]-?: T[K] extends V ? never : K
|
|
64
|
+
// }[keyof T];
|
|
65
|
+
|
|
66
|
+
// // type _ = KeysMatching<Class_NPP,Class_MSBPP[keyof Class_MSBPP]>
|
|
67
|
+
// /**
|
|
68
|
+
// * @see https://stackoverflow.com/a/56874389/14894786
|
|
69
|
+
// * @example
|
|
70
|
+
// * interface AnotherInterface {
|
|
71
|
+
// * narrower: 1;
|
|
72
|
+
// * exact: number;
|
|
73
|
+
// * wider: string | number;
|
|
74
|
+
// * }
|
|
75
|
+
// * type AnotherTypeWrite = KeysMatchingWrite<AnotherInterface, number>;
|
|
76
|
+
// * type AnotherTypeWrite = 'exact' | 'wider';
|
|
77
|
+
// * @todo KeysMatchingWrite
|
|
78
|
+
// */
|
|
79
|
+
// // eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
80
|
+
// type KeysMatchingWrite<T extends object, V> = {
|
|
81
|
+
// [K in keyof T]-?: [V] extends [T[K]] ? K : never
|
|
82
|
+
// }[keyof T];
|