@hublo/sentinel 1.4.0-alpha.25 → 1.4.0-alpha.27
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/bin/sentinel.js
CHANGED
|
@@ -5774,12 +5774,38 @@ function rewriteAssertionReturnValue(source, program) {
|
|
|
5774
5774
|
return { source: result, rewritten: captures.length - refusals.length, refusals };
|
|
5775
5775
|
}
|
|
5776
5776
|
|
|
5777
|
-
// src/roles/test/codemod/
|
|
5777
|
+
// src/roles/test/codemod/bare-mock-factory.ts
|
|
5778
5778
|
var MEMBER_TYPES2 = /* @__PURE__ */ new Set(["MemberExpression", "StaticMemberExpression"]);
|
|
5779
|
+
function isMockFactory(node) {
|
|
5780
|
+
if (node === void 0 || !MEMBER_TYPES2.has(node.type)) return false;
|
|
5781
|
+
const object = node.object;
|
|
5782
|
+
const property = node.property;
|
|
5783
|
+
if (object?.type !== "Identifier") return false;
|
|
5784
|
+
if (object.name !== "vi" && object.name !== "jest") return false;
|
|
5785
|
+
return property?.type === "Identifier" && property.name === "fn";
|
|
5786
|
+
}
|
|
5787
|
+
function invokeBareMockFactories(source, program) {
|
|
5788
|
+
const edits = [];
|
|
5789
|
+
walk(program, (node) => {
|
|
5790
|
+
if (node.type !== "CallExpression") return;
|
|
5791
|
+
for (const argument of node.arguments ?? []) {
|
|
5792
|
+
if (isMockFactory(argument)) edits.push(argument.end);
|
|
5793
|
+
}
|
|
5794
|
+
});
|
|
5795
|
+
if (edits.length === 0) return { source, rewritten: 0 };
|
|
5796
|
+
let result = source;
|
|
5797
|
+
for (const end of [...edits].sort((left, right) => right - left)) {
|
|
5798
|
+
result = `${result.slice(0, end)}()${result.slice(end)}`;
|
|
5799
|
+
}
|
|
5800
|
+
return { source: result, rewritten: edits.length };
|
|
5801
|
+
}
|
|
5802
|
+
|
|
5803
|
+
// src/roles/test/codemod/constructible-mocks.ts
|
|
5804
|
+
var MEMBER_TYPES3 = /* @__PURE__ */ new Set(["MemberExpression", "StaticMemberExpression"]);
|
|
5779
5805
|
function mockImplementationArrow(node) {
|
|
5780
5806
|
if (node.type !== "CallExpression") return void 0;
|
|
5781
5807
|
const callee = node.callee;
|
|
5782
|
-
if (callee === void 0 || !
|
|
5808
|
+
if (callee === void 0 || !MEMBER_TYPES3.has(callee.type)) return void 0;
|
|
5783
5809
|
const property = callee.property;
|
|
5784
5810
|
if (property?.type !== "Identifier" || property.name !== "mockImplementation") return void 0;
|
|
5785
5811
|
const [argument] = node.arguments ?? [];
|
|
@@ -5788,7 +5814,7 @@ function mockImplementationArrow(node) {
|
|
|
5788
5814
|
function assertedMockedClass(source, node) {
|
|
5789
5815
|
if (node.type !== "CallExpression") return false;
|
|
5790
5816
|
const callee = node.callee;
|
|
5791
|
-
if (callee === void 0 || !
|
|
5817
|
+
if (callee === void 0 || !MEMBER_TYPES3.has(callee.type)) return false;
|
|
5792
5818
|
const object = callee.object;
|
|
5793
5819
|
if (object === void 0) return false;
|
|
5794
5820
|
return /\bMockedClass\b/.test(source.slice(object.start, object.end));
|
|
@@ -5864,16 +5890,16 @@ function normaliseDeepImports(source) {
|
|
|
5864
5890
|
}
|
|
5865
5891
|
|
|
5866
5892
|
// src/roles/test/codemod/each-table-rows.ts
|
|
5867
|
-
var
|
|
5893
|
+
var MEMBER_TYPES4 = /* @__PURE__ */ new Set(["MemberExpression", "StaticMemberExpression"]);
|
|
5868
5894
|
var RUNNERS = /* @__PURE__ */ new Set(["it", "test", "describe"]);
|
|
5869
5895
|
function eachTable(node) {
|
|
5870
5896
|
if (node.type !== "CallExpression") return void 0;
|
|
5871
5897
|
const callee = node.callee;
|
|
5872
|
-
if (callee === void 0 || !
|
|
5898
|
+
if (callee === void 0 || !MEMBER_TYPES4.has(callee.type)) return void 0;
|
|
5873
5899
|
const property = callee.property;
|
|
5874
5900
|
if (property?.type !== "Identifier" || property.name !== "each") return void 0;
|
|
5875
5901
|
let object = callee.object;
|
|
5876
|
-
while (object !== void 0 &&
|
|
5902
|
+
while (object !== void 0 && MEMBER_TYPES4.has(object.type)) {
|
|
5877
5903
|
object = object.object;
|
|
5878
5904
|
}
|
|
5879
5905
|
if (object?.type !== "Identifier" || !RUNNERS.has(object.name)) return void 0;
|
|
@@ -5900,13 +5926,13 @@ function rewriteEachTableRows(source, program) {
|
|
|
5900
5926
|
}
|
|
5901
5927
|
|
|
5902
5928
|
// src/roles/test/codemod/each-title.ts
|
|
5903
|
-
var
|
|
5929
|
+
var MEMBER_TYPES5 = /* @__PURE__ */ new Set(["MemberExpression", "StaticMemberExpression"]);
|
|
5904
5930
|
function eachTitle(node) {
|
|
5905
5931
|
if (node.type !== "CallExpression") return void 0;
|
|
5906
5932
|
const inner = node.callee;
|
|
5907
5933
|
if (inner?.type !== "CallExpression") return void 0;
|
|
5908
5934
|
const member = inner.callee;
|
|
5909
|
-
if (member === void 0 || !
|
|
5935
|
+
if (member === void 0 || !MEMBER_TYPES5.has(member.type)) return void 0;
|
|
5910
5936
|
const property = member.property;
|
|
5911
5937
|
if (property?.type !== "Identifier" || property.name !== "each") return void 0;
|
|
5912
5938
|
const [title] = node.arguments ?? [];
|
|
@@ -5959,14 +5985,14 @@ function rewriteEachTitles(source, program) {
|
|
|
5959
5985
|
|
|
5960
5986
|
// src/roles/test/codemod/empty-mock-implementation.ts
|
|
5961
5987
|
var METHODS = /* @__PURE__ */ new Set(["mockImplementation", "mockImplementationOnce"]);
|
|
5962
|
-
var
|
|
5988
|
+
var MEMBER_TYPES6 = /* @__PURE__ */ new Set(["MemberExpression", "StaticMemberExpression"]);
|
|
5963
5989
|
function rewriteEmptyMockImplementation(source, program) {
|
|
5964
5990
|
const insertAt = [];
|
|
5965
5991
|
walk(program, (node) => {
|
|
5966
5992
|
if (node.type !== "CallExpression") return;
|
|
5967
5993
|
if ((node.arguments ?? []).length > 0) return;
|
|
5968
5994
|
const callee = node.callee;
|
|
5969
|
-
if (callee === void 0 || !
|
|
5995
|
+
if (callee === void 0 || !MEMBER_TYPES6.has(callee.type)) return;
|
|
5970
5996
|
const property = callee.property;
|
|
5971
5997
|
if (property?.type !== "Identifier" || !METHODS.has(property.name)) return;
|
|
5972
5998
|
insertAt.push(node.end - 1);
|
|
@@ -5979,12 +6005,12 @@ function rewriteEmptyMockImplementation(source, program) {
|
|
|
5979
6005
|
}
|
|
5980
6006
|
|
|
5981
6007
|
// src/roles/test/codemod/fake-timer-options.ts
|
|
5982
|
-
var
|
|
6008
|
+
var MEMBER_TYPES7 = /* @__PURE__ */ new Set(["MemberExpression", "StaticMemberExpression"]);
|
|
5983
6009
|
var TIMER_CALLS = /* @__PURE__ */ new Set(["useFakeTimers"]);
|
|
5984
6010
|
function timerOptions(node) {
|
|
5985
6011
|
if (node.type !== "CallExpression") return void 0;
|
|
5986
6012
|
const callee = node.callee;
|
|
5987
|
-
if (callee === void 0 || !
|
|
6013
|
+
if (callee === void 0 || !MEMBER_TYPES7.has(callee.type)) return void 0;
|
|
5988
6014
|
const object = callee.object;
|
|
5989
6015
|
const property = callee.property;
|
|
5990
6016
|
if (object?.type !== "Identifier") return void 0;
|
|
@@ -6328,7 +6354,7 @@ function hoistCapturedBindings(source, program, factories, bindings, imported) {
|
|
|
6328
6354
|
|
|
6329
6355
|
// src/roles/test/codemod/hook-return-value.ts
|
|
6330
6356
|
var HOOKS = /* @__PURE__ */ new Set(["beforeEach", "afterEach", "beforeAll", "afterAll"]);
|
|
6331
|
-
var
|
|
6357
|
+
var MEMBER_TYPES8 = /* @__PURE__ */ new Set(["MemberExpression", "StaticMemberExpression"]);
|
|
6332
6358
|
function hookCallback(node) {
|
|
6333
6359
|
if (node.type !== "CallExpression") return void 0;
|
|
6334
6360
|
const callee = node.callee;
|
|
@@ -6339,7 +6365,7 @@ function hookCallback(node) {
|
|
|
6339
6365
|
function configuresAMock(body) {
|
|
6340
6366
|
if (body.type !== "CallExpression") return false;
|
|
6341
6367
|
const callee = body.callee;
|
|
6342
|
-
if (callee === void 0 || !
|
|
6368
|
+
if (callee === void 0 || !MEMBER_TYPES8.has(callee.type)) return false;
|
|
6343
6369
|
const property = callee.property;
|
|
6344
6370
|
return property?.type === "Identifier" && /^mock[A-Z]/.test(property.name);
|
|
6345
6371
|
}
|
|
@@ -6554,7 +6580,7 @@ function isCommonJsPackage(fromFile, specifier) {
|
|
|
6554
6580
|
}
|
|
6555
6581
|
return false;
|
|
6556
6582
|
}
|
|
6557
|
-
var
|
|
6583
|
+
var MEMBER_TYPES9 = /* @__PURE__ */ new Set(["MemberExpression", "StaticMemberExpression"]);
|
|
6558
6584
|
var ASYNC_REPLACEMENTS = {
|
|
6559
6585
|
requireActual: "importActual",
|
|
6560
6586
|
requireMock: "importMock"
|
|
@@ -6564,7 +6590,7 @@ function mockedSpecifiers(program) {
|
|
|
6564
6590
|
walk(program, (node) => {
|
|
6565
6591
|
if (node.type !== "CallExpression") return;
|
|
6566
6592
|
const callee = node.callee;
|
|
6567
|
-
if (callee === void 0 || !
|
|
6593
|
+
if (callee === void 0 || !MEMBER_TYPES9.has(callee.type)) return;
|
|
6568
6594
|
const object = callee.object;
|
|
6569
6595
|
const property = callee.property;
|
|
6570
6596
|
if (object?.type !== "Identifier") return;
|
|
@@ -6601,7 +6627,7 @@ function bareRequire(node) {
|
|
|
6601
6627
|
function mockFactoryReturn(node) {
|
|
6602
6628
|
if (node.type !== "CallExpression") return void 0;
|
|
6603
6629
|
const callee = node.callee;
|
|
6604
|
-
if (callee === void 0 || !
|
|
6630
|
+
if (callee === void 0 || !MEMBER_TYPES9.has(callee.type)) return void 0;
|
|
6605
6631
|
const object = callee.object;
|
|
6606
6632
|
const property = callee.property;
|
|
6607
6633
|
if (object?.type !== "Identifier") return void 0;
|
|
@@ -6711,7 +6737,7 @@ function applyNamedRules(source, program, fileName = "") {
|
|
|
6711
6737
|
}
|
|
6712
6738
|
return;
|
|
6713
6739
|
}
|
|
6714
|
-
if (!
|
|
6740
|
+
if (!MEMBER_TYPES9.has(node.type)) return;
|
|
6715
6741
|
const object = node.object;
|
|
6716
6742
|
if (object !== void 0) readsANameOffIt.add(object);
|
|
6717
6743
|
});
|
|
@@ -6782,13 +6808,13 @@ function applyNamedRules(source, program, fileName = "") {
|
|
|
6782
6808
|
}
|
|
6783
6809
|
|
|
6784
6810
|
// src/roles/test/codemod/isolate-modules.ts
|
|
6785
|
-
var
|
|
6811
|
+
var MEMBER_TYPES10 = /* @__PURE__ */ new Set(["MemberExpression", "StaticMemberExpression"]);
|
|
6786
6812
|
var ISOLATORS = /* @__PURE__ */ new Set(["isolateModules", "isolateModulesAsync"]);
|
|
6787
6813
|
var FUNCTIONS2 = /* @__PURE__ */ new Set(["ArrowFunctionExpression", "FunctionExpression"]);
|
|
6788
6814
|
function isolatingCall(node) {
|
|
6789
6815
|
if (node.type !== "CallExpression") return void 0;
|
|
6790
6816
|
const callee = node.callee;
|
|
6791
|
-
if (callee === void 0 || !
|
|
6817
|
+
if (callee === void 0 || !MEMBER_TYPES10.has(callee.type)) return void 0;
|
|
6792
6818
|
const object = callee.object;
|
|
6793
6819
|
const property = callee.property;
|
|
6794
6820
|
if (object?.type !== "Identifier" || object.name !== "jest") return void 0;
|
|
@@ -6799,7 +6825,7 @@ function isolatingCall(node) {
|
|
|
6799
6825
|
function unusableIsolatingCall(node) {
|
|
6800
6826
|
if (node.type !== "CallExpression") return void 0;
|
|
6801
6827
|
const callee = node.callee;
|
|
6802
|
-
if (callee === void 0 || !
|
|
6828
|
+
if (callee === void 0 || !MEMBER_TYPES10.has(callee.type)) return void 0;
|
|
6803
6829
|
const object = callee.object;
|
|
6804
6830
|
const property = callee.property;
|
|
6805
6831
|
if (object?.type !== "Identifier" || object.name !== "jest") return void 0;
|
|
@@ -6850,11 +6876,11 @@ ${indent}await (${callback})()`
|
|
|
6850
6876
|
}
|
|
6851
6877
|
|
|
6852
6878
|
// src/roles/test/codemod/mock-as-value.ts
|
|
6853
|
-
var
|
|
6879
|
+
var MEMBER_TYPES11 = /* @__PURE__ */ new Set(["MemberExpression", "StaticMemberExpression"]);
|
|
6854
6880
|
function isViMockCall(node) {
|
|
6855
6881
|
if (node?.type !== "CallExpression") return false;
|
|
6856
6882
|
const callee = node.callee;
|
|
6857
|
-
if (callee === void 0 || !
|
|
6883
|
+
if (callee === void 0 || !MEMBER_TYPES11.has(callee.type)) return false;
|
|
6858
6884
|
const object = callee.object;
|
|
6859
6885
|
const property = callee.property;
|
|
6860
6886
|
return object?.type === "Identifier" && object.name === "vi" && property?.type === "Identifier" && (property.name === "mock" || property.name === "doMock");
|
|
@@ -6879,7 +6905,7 @@ function rewriteMockAsValue(source, program) {
|
|
|
6879
6905
|
const memberUses = /* @__PURE__ */ new Map();
|
|
6880
6906
|
const otherUses = /* @__PURE__ */ new Map();
|
|
6881
6907
|
walk(program, (node) => {
|
|
6882
|
-
if (
|
|
6908
|
+
if (MEMBER_TYPES11.has(node.type)) {
|
|
6883
6909
|
const object = node.object;
|
|
6884
6910
|
if (object?.type === "Identifier" && bindings.has(object.name)) {
|
|
6885
6911
|
const list = memberUses.get(object.name) ?? [];
|
|
@@ -6925,12 +6951,12 @@ function rewriteMockAsValue(source, program) {
|
|
|
6925
6951
|
}
|
|
6926
6952
|
|
|
6927
6953
|
// src/roles/test/codemod/mock-factory-default.ts
|
|
6928
|
-
var
|
|
6954
|
+
var MEMBER_TYPES12 = /* @__PURE__ */ new Set(["MemberExpression", "StaticMemberExpression"]);
|
|
6929
6955
|
var BINDING = "sentinelMockedModule";
|
|
6930
6956
|
function mockCall(node) {
|
|
6931
6957
|
if (node.type !== "CallExpression") return void 0;
|
|
6932
6958
|
const callee = node.callee;
|
|
6933
|
-
if (callee === void 0 || !
|
|
6959
|
+
if (callee === void 0 || !MEMBER_TYPES12.has(callee.type)) return void 0;
|
|
6934
6960
|
const property = callee.property;
|
|
6935
6961
|
if (property?.type !== "Identifier" || property.name !== "mock") return void 0;
|
|
6936
6962
|
const object = callee.object;
|
|
@@ -7043,7 +7069,7 @@ function rewriteMockFactoryDefault(source, program, defaultImported) {
|
|
|
7043
7069
|
|
|
7044
7070
|
// src/roles/test/codemod/mock-promise-resolve.ts
|
|
7045
7071
|
var MOCK_FACTORY = /* @__PURE__ */ new Set(["fn", "spyOn"]);
|
|
7046
|
-
function
|
|
7072
|
+
function isMockFactory2(source, node) {
|
|
7047
7073
|
if (node.type !== "CallExpression") return false;
|
|
7048
7074
|
const callee = node.callee;
|
|
7049
7075
|
if (callee?.type !== "MemberExpression") return false;
|
|
@@ -7086,7 +7112,7 @@ function resolvedValue(source, executor) {
|
|
|
7086
7112
|
function rewriteMockPromiseResolve(source, program) {
|
|
7087
7113
|
const edits = [];
|
|
7088
7114
|
walk(program, (node) => {
|
|
7089
|
-
if (!
|
|
7115
|
+
if (!isMockFactory2(source, node)) return;
|
|
7090
7116
|
for (const argument of node.arguments ?? []) {
|
|
7091
7117
|
walk(argument, (inner) => {
|
|
7092
7118
|
if (inner.type !== "NewExpression") return;
|
|
@@ -7114,11 +7140,11 @@ function rewriteMockPromiseResolve(source, program) {
|
|
|
7114
7140
|
}
|
|
7115
7141
|
|
|
7116
7142
|
// src/roles/test/codemod/mocked-module-binding.ts
|
|
7117
|
-
var
|
|
7143
|
+
var MEMBER_TYPES13 = /* @__PURE__ */ new Set(["MemberExpression", "StaticMemberExpression"]);
|
|
7118
7144
|
function mockedSpecifier(source, node) {
|
|
7119
7145
|
if (node.type !== "CallExpression") return void 0;
|
|
7120
7146
|
const callee = node.callee;
|
|
7121
|
-
if (callee === void 0 || !
|
|
7147
|
+
if (callee === void 0 || !MEMBER_TYPES13.has(callee.type)) return void 0;
|
|
7122
7148
|
const object = callee.object;
|
|
7123
7149
|
const property = callee.property;
|
|
7124
7150
|
if (object?.type !== "Identifier") return void 0;
|
|
@@ -7176,7 +7202,7 @@ function annotateMockedBindings(source, program) {
|
|
|
7176
7202
|
// src/roles/test/codemod/propagate-await.ts
|
|
7177
7203
|
import { parseSync as parseSync5 } from "oxc-parser";
|
|
7178
7204
|
var FUNCTIONS3 = /* @__PURE__ */ new Set(["ArrowFunctionExpression", "FunctionExpression", "FunctionDeclaration"]);
|
|
7179
|
-
var
|
|
7205
|
+
var MEMBER_TYPES14 = /* @__PURE__ */ new Set(["MemberExpression", "StaticMemberExpression"]);
|
|
7180
7206
|
var ALREADY_A_PROMISE = /* @__PURE__ */ new Set(["then", "catch", "finally"]);
|
|
7181
7207
|
function asyncFunctionNames(program) {
|
|
7182
7208
|
const names = /* @__PURE__ */ new Set();
|
|
@@ -7250,7 +7276,7 @@ function alreadyHandled(call, parent) {
|
|
|
7250
7276
|
if (parent === void 0) return false;
|
|
7251
7277
|
if (parent.type === "AwaitExpression") return true;
|
|
7252
7278
|
if (parent.type === "ReturnStatement" || parent.type === "ArrowFunctionExpression") return true;
|
|
7253
|
-
if (
|
|
7279
|
+
if (MEMBER_TYPES14.has(parent.type) && parent.object === call) {
|
|
7254
7280
|
const property = parent.property;
|
|
7255
7281
|
return property?.type === "Identifier" && ALREADY_A_PROMISE.has(property.name);
|
|
7256
7282
|
}
|
|
@@ -7303,7 +7329,7 @@ function propagateAwait(fileName, source, original, elsewhere = /* @__PURE__ */
|
|
|
7303
7329
|
import { readFileSync as readFileSync24, readdirSync as readdirSync4, statSync as statSync4 } from "node:fs";
|
|
7304
7330
|
import { createRequire as createRequire5 } from "node:module";
|
|
7305
7331
|
import { dirname as dirname5, join as join30 } from "node:path";
|
|
7306
|
-
var
|
|
7332
|
+
var MEMBER_TYPES15 = /* @__PURE__ */ new Set(["MemberExpression", "StaticMemberExpression"]);
|
|
7307
7333
|
var PACKAGE_SUBPATH = /^(@[^/]+\/[^/]+|[^@.][^/]*)\/(.+)$/;
|
|
7308
7334
|
var PURE_REEXPORT = /^module\.exports\s*=\s*require\(\s*(['"])([^'"]+)\1\s*\)\s*;?$/;
|
|
7309
7335
|
function mockCalls(program) {
|
|
@@ -7311,7 +7337,7 @@ function mockCalls(program) {
|
|
|
7311
7337
|
walk(program, (node) => {
|
|
7312
7338
|
if (node.type !== "CallExpression") return;
|
|
7313
7339
|
const callee = node.callee;
|
|
7314
|
-
if (callee === void 0 || !
|
|
7340
|
+
if (callee === void 0 || !MEMBER_TYPES15.has(callee.type)) return;
|
|
7315
7341
|
const object = callee.object;
|
|
7316
7342
|
const property = callee.property;
|
|
7317
7343
|
if (object?.type !== "Identifier") return;
|
|
@@ -7804,7 +7830,10 @@ function migrateTestFile(fileName, source, defaultImported = /* @__PURE__ */ new
|
|
|
7804
7830
|
const afterHoist = parse2(fileName, hoist.source);
|
|
7805
7831
|
if (afterHoist === void 0) return unparsable("hoisting captured bindings");
|
|
7806
7832
|
const mockedBindings = annotateMockedBindings(hoist.source, afterHoist);
|
|
7807
|
-
const
|
|
7833
|
+
const afterBindings = parse2(fileName, mockedBindings.source);
|
|
7834
|
+
if (afterBindings === void 0) return unparsable("mocked module bindings");
|
|
7835
|
+
const bareFactories = invokeBareMockFactories(mockedBindings.source, afterBindings);
|
|
7836
|
+
const withImport = injectTypeImport(fileName, bareFactories.source, [
|
|
7808
7837
|
...renamed.typeImports,
|
|
7809
7838
|
...spyTypes.typeImports,
|
|
7810
7839
|
...mockedBindings.typeImports
|
|
@@ -7831,6 +7860,7 @@ function migrateTestFile(fileName, source, defaultImported = /* @__PURE__ */ new
|
|
|
7831
7860
|
...hooks.rewritten > 0 ? ["hook body, so it does not return its mock"] : [],
|
|
7832
7861
|
...spyTypes.rewritten > 0 ? ["SpyInstance<T> as a signature, not a return type"] : [],
|
|
7833
7862
|
...mockedBindings.rewritten > 0 ? ["a mocked module binding, typed as mocked"] : [],
|
|
7863
|
+
...bareFactories.rewritten > 0 ? ["vi.fn passed as a value, invoked"] : [],
|
|
7834
7864
|
...awaited.rewritten > 0 ? ["await propagated to a helper that became async"] : [],
|
|
7835
7865
|
...barrels.added.map((alias) => `mock carried to ${alias}, which re-exports the mocked file`),
|
|
7836
7866
|
...fakeTimers.translated
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hublo/sentinel",
|
|
3
|
-
"version": "1.4.0-alpha.
|
|
3
|
+
"version": "1.4.0-alpha.27",
|
|
4
4
|
"description": "One CLI that guards code health across Hublo repos: shared lint/typescript/build/test presets, static & dynamic analysis, and architecture checks.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|