@filipebraida/adonis-function-points 0.3.0 → 0.5.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 CHANGED
@@ -6,6 +6,119 @@ release moves the number for unchanged code, the rule set version moves with it
6
6
  otherwise the difference would measure the tool's change rather than the work, and
7
7
  that difference becomes an invoice.
8
8
 
9
+ ## 0.5.0
10
+
11
+ **Rule set `afp@1.4.0`.** Two classification defects are fixed and both move numbers,
12
+ so a 0.4.0 baseline has to be recounted.
13
+
14
+ Found by auditing a production count function by function against the code, rather than
15
+ by reading the report's warnings — which is where the previous rounds had been looking.
16
+
17
+ ### Fixed
18
+
19
+ - **Maintenance was decided per REQUEST instead of per store.** `behavior.writes`
20
+ decides EI against EO and was also read as "this store is maintained", so every store
21
+ a writing transaction touched became an ILF. A reference table merely READ by a route
22
+ that writes something else counted as maintained. On a production application this
23
+ left exactly one EIF in the whole count, which should have been the signal.
24
+ - **Seeders, tests and factories counted as maintenance.** The project-wide pass read a
25
+ seeder's inserts as the application maintaining a table, so reference data only the
26
+ seed populates came out as an ILF — which the CPM does not allow. The filter on scan
27
+ roots drops `tests/` and `database/` only at the ROOT, and a domain-module layout puts
28
+ both inside `app/`. It now applies at any depth.
29
+ - **The override warning counted floors that were already answered**, said "one schema"
30
+ whatever it was given, and therefore fired on a configuration that was complete.
31
+ - **`opaqueReviewed` matching nothing was silent.** `detFromSchema` already warns when
32
+ it names a schema that is not declared; a review naming a field that does not exist
33
+ reviewed nothing while the warning kept firing, which reads as the tool ignoring the
34
+ configuration.
35
+ - **A review was invisible in `fp:explain`.** Its reason appeared nowhere, which defeats
36
+ requiring one. Reviewed floors are now marked `(opaque, reviewed)` and the reason is
37
+ printed — without being counted in the "Declared by override" share, since a review
38
+ declares no number.
39
+
40
+ ### Documented
41
+
42
+ - **In CI, prefer the standalone binary.** `node ace` validates `start/env.ts` before
43
+ running any command, so `node ace fp:count` fails on a missing environment variable
44
+ that has nothing to do with counting — measured on a production application, it
45
+ stopped at `Missing environment variable "AUTHZ_STORE"` and never reached the
46
+ command. The `fp:*` commands declare `startApp: false`, which is not enough. The
47
+ README said the two front-ends were interchangeable; for a pipeline that only checks
48
+ out code, they are not.
49
+
50
+ ### New
51
+
52
+ - **`CallResolver.technicalWrite()`** declares that a write is not what the transaction
53
+ is for. §6.5.3 reads any write as an EI, which misreads a screen that records the
54
+ visit; the CPM asks about primary intent. The fact is declared about the CALL, so a
55
+ bookkeeping helper called from several screens is declared once. It does not hide the
56
+ write: the store stays an ILF and stays an FTR.
57
+ - **`boundary.business` says when it contradicts the code.** It accepted without comment
58
+ a table nothing in the application writes — which is how two read-only lookup tables
59
+ were declared as business data on the belief they had a CRUD, when the routes were
60
+ `.only(['index', 'show'])`. The declaration is still honoured; the fact is reported.
61
+
62
+ ## 0.4.0
63
+
64
+ **Rule set `afp@1.3.0`.** Conditional validator groups now count, and a nested
65
+ schema is recognised however the formatter wrapped it — so a 0.3.0 baseline has to
66
+ be recounted.
67
+
68
+ Five items reported from real use of 0.3.0, three of them defects.
69
+
70
+ ### Fixed
71
+
72
+ - **A newline decided whether a field counted.** The recogniser for a nested schema
73
+ was a regex over the property's source text (`/vine\.object/`), and Prettier breaks
74
+ a long chain across lines — `data: vine` then `.object({})` — so the regex missed
75
+ and the field was counted as one leaf instead of its nested ones, and never marked
76
+ opaque. Decided by structure now: is this literal the argument of a call named
77
+ `object`? The same applied to `.merge(…)` and `group.if(…)`, which had the same
78
+ kind of check. A count that depends on where the formatter put a newline is not a
79
+ measurement — the reason the implementation-scope hash strips whitespace before
80
+ hashing.
81
+ - **The list of unreadable DETs ignored the overrides that answered it.** It was
82
+ computed before `applyOverrides` ran, so a function whose floor `detFromSchema` had
83
+ already replaced still appeared under "this is a FLOOR", telling the reader to map
84
+ something already mapped. It caused a real misreading of a production report, by
85
+ the author of this code. It now runs after the overrides, is grouped by FUNCTION,
86
+ and states per function how many were replaced by an override, how many reviewed,
87
+ and how many are still unanswered — only the last being a request to do anything.
88
+ - **Emitted artefacts carried absolute paths.** `CountSource.app` is documented as
89
+ never being one, because that says where the machine keeps its files and travels
90
+ with every artefact sent anywhere — and the rule was applied to that one field. A
91
+ production count carried **858** absolute paths in its traces; an inventory
92
+ carried **2036** across ten fields, including the data-store `id`. Every path that
93
+ leaves is now relative to the application root, and the internal absolute form is
94
+ untouched because that is what ts-morph resolves against.
95
+ - **`vine.group` and `.merge()` were not read.**
96
+ `vine.object({}).merge(vine.group([vine.group.if(p, {…})]))` reported the whole
97
+ validator as an open input object: five fields counted as one, and the report said
98
+ they were data when they are in the code. The branches are mutually exclusive at
99
+ runtime and the transaction can carry any of them, so §7.2 counts their union — a
100
+ field two branches share counts once. The group usually lives in an unexported
101
+ constant beside the validator, so the reference is resolved in the validator's own
102
+ file rather than the caller's.
103
+ - **`fp:explain` matched by substring even when the exact name existed.** Asking
104
+ about `POST /orders/:param/submit` returned four functions, because
105
+ `/submit-ready` and `/submit-ready/return` contain it. An exact name now wins
106
+ outright; the substring search is the fallback.
107
+
108
+ ### New
109
+
110
+ - **`detFromSchema` accepts a list**, unioned by leaf path. An ILF's DETs are the
111
+ fields the user recognises in the file, and an application with one schema per
112
+ template recognises all of them. Pointing at the largest and justifying it in
113
+ `reason` gives the same answer only while they land in the same band — reasoning
114
+ the configuration should not have to carry.
115
+ - **`overrides.<fn>.opaqueReviewed`** records that someone looked at an opaque DET
116
+ and decided 1 is right. 1 DET is a floor and `fp:count` says so on every run, but
117
+ some of those columns really are one field, and a warning that cannot be answered
118
+ is one the team learns to scroll past. It moves no number, it is not counted as a
119
+ declared override in the "Declared by override" share, and the volume reviewed is
120
+ still printed.
121
+
9
122
  ## 0.3.0
10
123
 
11
124
  **Rule set `afp@1.2.0`.** Three counting fixes move the number for unchanged code,
package/README.md CHANGED
@@ -13,7 +13,7 @@ node ace fp:count
13
13
 
14
14
  ```
15
15
  Unadjusted count: 46 FP
16
- Ruleset: afp@1.2.0
16
+ Ruleset: afp@1.4.0
17
17
 
18
18
  type n FP
19
19
  ILF 2 14
@@ -63,11 +63,21 @@ For CI, or a one-off count on a project you do not want to touch:
63
63
  npx @filipebraida/adonis-function-points count --root ./my-app
64
64
  ```
65
65
 
66
- Nothing is booted either way — the engine only reads files — so a standalone
67
- run needs no `.env`, no database, and no install inside the analysed project.
68
- The standalone binary **does not replace installing**: a project that installs
69
- the package keeps the `node ace fp:*` commands, and both front-ends call the
70
- same code, so they cannot disagree about a number.
66
+ The engine itself boots nothing — it only reads files — and the standalone binary
67
+ needs no `.env`, no database, and no install inside the analysed project. The
68
+ `fp:*` commands declare `startApp: false` for the same reason.
69
+
70
+ **In CI, prefer the standalone binary.** Not for convenience: `node ace` validates
71
+ `start/env.ts` before it runs any command, so `node ace fp:count` fails on a
72
+ missing environment variable that has nothing to do with counting. Measured on a
73
+ production application, it stopped at `Missing environment variable "AUTHZ_STORE"`
74
+ and never reached the command. A pipeline that only checks out the code has no
75
+ secrets, and does not need them to count.
76
+
77
+ The standalone binary **does not replace installing**: a project that installs the
78
+ package keeps the `node ace fp:*` commands — which is the right front-end at a
79
+ developer's terminal, where the `.env` is already there — and both call the same
80
+ code, so they cannot disagree about a number.
71
81
 
72
82
  ```
73
83
  adonis-function-points <command> [options]
@@ -75,6 +85,7 @@ adonis-function-points <command> [options]
75
85
  count count the unadjusted function points
76
86
  inventory the raw facts: stores, routes, tracing coverage
77
87
  explain <name> why one function was counted that way
88
+ metrics density, coupling and conformance, from the same run
78
89
  diff <previous.json> additions / modifications / deletions, and billable FP
79
90
  calibrate <samples.csv> correction factors against a manual count
80
91
 
@@ -14,27 +14,27 @@
14
14
  const commands = [
15
15
  {
16
16
  commandName: "fp:inventory",
17
- importer: () => import("../fp_inventory-Bu6O1Nn0.js")
17
+ importer: () => import("../fp_inventory-CPtmuuke.js")
18
18
  },
19
19
  {
20
20
  commandName: "fp:metrics",
21
- importer: () => import("../fp_metrics-MGDppfSa.js")
21
+ importer: () => import("../fp_metrics-et8F1Wvt.js")
22
22
  },
23
23
  {
24
24
  commandName: "fp:count",
25
- importer: () => import("../fp_count-D21tQ_pv.js")
25
+ importer: () => import("../fp_count-ChtblhZV.js")
26
26
  },
27
27
  {
28
28
  commandName: "fp:explain",
29
- importer: () => import("../fp_explain-BwFs-LW-.js")
29
+ importer: () => import("../fp_explain-DZJ--0-S.js")
30
30
  },
31
31
  {
32
32
  commandName: "fp:diff",
33
- importer: () => import("../fp_diff-D0pHGMgi.js")
33
+ importer: () => import("../fp_diff-Dt7J4IWu.js")
34
34
  },
35
35
  {
36
36
  commandName: "fp:calibrate",
37
- importer: () => import("../fp_calibrate-iFAec0tA.js")
37
+ importer: () => import("../fp_calibrate-DUbHiifm.js")
38
38
  }
39
39
  ];
40
40
  let cache = null;
@@ -1,4 +1,4 @@
1
- import { s as printResult, t as runCalibrate } from "./runners-CmxNHuuq.js";
1
+ import { s as printResult, t as runCalibrate } from "./runners-DIt1G85i.js";
2
2
  import { n as printerFor, t as __decorate } from "./decorate-D6enDn9D.js";
3
3
  import { BaseCommand, args } from "@adonisjs/core/ace";
4
4
  //#region commands/fp_calibrate.ts
@@ -1,4 +1,4 @@
1
- import { n as runCount, s as printResult } from "./runners-CmxNHuuq.js";
1
+ import { n as runCount, s as printResult } from "./runners-DIt1G85i.js";
2
2
  import { n as printerFor, t as __decorate } from "./decorate-D6enDn9D.js";
3
3
  import { BaseCommand, flags } from "@adonisjs/core/ace";
4
4
  //#region commands/fp_count.ts
@@ -1,4 +1,4 @@
1
- import { r as runDiff, s as printResult } from "./runners-CmxNHuuq.js";
1
+ import { r as runDiff, s as printResult } from "./runners-DIt1G85i.js";
2
2
  import { n as printerFor, t as __decorate } from "./decorate-D6enDn9D.js";
3
3
  import { BaseCommand, args } from "@adonisjs/core/ace";
4
4
  //#region commands/fp_diff.ts
@@ -1,4 +1,4 @@
1
- import { i as runExplain, s as printResult } from "./runners-CmxNHuuq.js";
1
+ import { i as runExplain, s as printResult } from "./runners-DIt1G85i.js";
2
2
  import { n as printerFor, t as __decorate } from "./decorate-D6enDn9D.js";
3
3
  import { BaseCommand, args } from "@adonisjs/core/ace";
4
4
  //#region commands/fp_explain.ts
@@ -1,4 +1,4 @@
1
- import { a as runInventory, s as printResult } from "./runners-CmxNHuuq.js";
1
+ import { a as runInventory, s as printResult } from "./runners-DIt1G85i.js";
2
2
  import { n as printerFor, t as __decorate } from "./decorate-D6enDn9D.js";
3
3
  import { BaseCommand, flags } from "@adonisjs/core/ace";
4
4
  //#region commands/fp_inventory.ts
@@ -1,4 +1,4 @@
1
- import { o as runMetrics, s as printResult } from "./runners-CmxNHuuq.js";
1
+ import { o as runMetrics, s as printResult } from "./runners-DIt1G85i.js";
2
2
  import { n as printerFor, t as __decorate } from "./decorate-D6enDn9D.js";
3
3
  import { BaseCommand, flags } from "@adonisjs/core/ace";
4
4
  //#region commands/fp_metrics.ts
package/build/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { configure } from "./configure.js";
2
2
  import { a as AEP_FACTORS, c as diffCounts, i as measureStructure, n as parseSamples, o as IncomparableRulesetsError, r as measureConformance, s as IncomparableSourcesError, t as calibrate, u as defineConfig } from "./calibration-8eV8CEix.js";
3
3
  import "./src/types.js";
4
- import { t as BUILTIN_CALL_RESOLVERS } from "./resolvers-CRB6lXoo.js";
5
- import { i as RULESET_VERSION, n as analyze, r as RULESET, t as CoverageTooLowError } from "./pipeline-CIAydCcT.js";
4
+ import { t as BUILTIN_CALL_RESOLVERS } from "./resolvers-PJwo2Z8R.js";
5
+ import { i as RULESET_VERSION, n as analyze, r as RULESET, t as CoverageTooLowError } from "./pipeline-CNTBhs6o.js";
6
6
  export { AEP_FACTORS, BUILTIN_CALL_RESOLVERS, CoverageTooLowError, IncomparableRulesetsError, IncomparableSourcesError, RULESET, RULESET_VERSION, analyze, calibrate, configure, defineConfig, diffCounts, measureConformance, measureStructure, parseSamples };