@produtype/core 0.7.0 → 0.7.1

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.
@@ -135,7 +135,10 @@ function parsePyproject(text) {
135
135
  return deps;
136
136
  }
137
137
  function isTestOrExamplePath(file) {
138
- return /(^|\/)(__tests__|tests?|test-data|fixtures|frontend-example)(\/|$)/i.test(file)
138
+ // `__mocks__` was missing, and a mock is the most misleading file in a repository:
139
+ // `application_fee_percent: null` inside a Stripe fixture made an open-source CRM read
140
+ // as a marketplace taking a cut. A field set to null is evidence of absence.
141
+ return /(^|\/)(__tests__|__mocks__|mocks?|tests?|test-data|fixtures|frontend-example)(\/|$)/i.test(file)
139
142
  || /(^|\/)test[-_][^/]+\.(ts|tsx|js|jsx|mjs|cjs|py)$/i.test(file)
140
143
  || /\.(test|spec)\.(ts|tsx|js|jsx|mjs|cjs|py)$/i.test(file);
141
144
  }
@@ -36,15 +36,34 @@ async function detectMultiRole(ctx) {
36
36
  for (const hit of [...sellerHits, ...buyerHits]) {
37
37
  evidence.push({ type: 'snippet', value: hit.snippet, file: hit.file, line: hit.line });
38
38
  }
39
- const roleFiles = ctx.files.all
40
- .filter((file) => /(seller|merchant|storefront)/i.test(file))
41
- .slice(0, 20);
39
+ /**
40
+ * File names that suggest a supply side — read from the analysed sources, not from
41
+ * every path in the repository.
42
+ *
43
+ * `twentyhq/twenty`, an open-source CRM, ships an example real-estate app whose
44
+ * `roles/seller.role.ts` matched here. Scanning `files.all` meant any path anywhere
45
+ * counted, including bundled demos and vendored code.
46
+ */
47
+ const roleFiles = scope.filter((file) => /(seller|merchant|storefront)/i.test(file)).slice(0, 20);
42
48
  for (const file of roleFiles)
43
49
  evidence.push({ type: 'file', value: file });
44
50
  // Both sides must appear for a confident signal: a supply-side vocabulary on its own
45
51
  // also fits a plain catalogue or CMS, so it downgrades to partial rather than present.
46
- const bothSides = sellerHits.length > 0 && buyerHits.length > 0;
47
- const oneSide = sellerHits.length > 0 || buyerHits.length > 0 || roleFiles.length > 0;
52
+ /**
53
+ * Two sides are not one sentence.
54
+ *
55
+ * `documenso`, an open-source document-signing product, came out a marketplace with
56
+ * high confidence on a single line: a comment in a field-detection schema listing
57
+ * `"Tenant", "Landlord", "Buyer", "Seller"` as examples of labels found in the
58
+ * documents its users sign. One line matched both sides, and one line is one
59
+ * mention.
60
+ */
61
+ const vocabularyFiles = new Set([...sellerHits, ...buyerHits].map((hit) => hit.file));
62
+ const bothSides = sellerHits.length > 0 && buyerHits.length > 0 && vocabularyFiles.size >= 2;
63
+ // A file name on its own is not a role either. Twenty had four such names and no
64
+ // buyer or seller vocabulary anywhere in its code, and came out a marketplace:
65
+ // naming a file is cheaper than building a two-sided product.
66
+ const oneSide = vocabularyFiles.size >= 2;
48
67
  return {
49
68
  key: 'marketplace.multiRole',
50
69
  present: oneSide,
@@ -78,7 +97,18 @@ async function detectPayout(ctx) {
78
97
  }
79
98
  async function detectCommission(ctx) {
80
99
  const evidence = [];
81
- const hits = await (0, textSearch_1.searchInFiles)(ctx.root, ctx.files.source, [/\bcommission/i, /application_fee/i, /\bplatform_?fee/i, /\btake_?rate/i, /\bservice_?fee/i], 20);
100
+ const hits = await (0, textSearch_1.searchInFiles)(ctx.root, ctx.files.source, [
101
+ // "Commission" is also an institution. The privacy policy of an open-source CRM
102
+ // said "European Commission, relying on an adequacy decision" and was read as a
103
+ // platform taking a cut, sixteen times over.
104
+ /commission[_\s]?(rate|fee|percent|amount|bps)/i,
105
+ /(rate|fee|percent|amount)[_\s]?commission/i,
106
+ /\bcommission[A-Z]/,
107
+ /application_fee/i,
108
+ /\bplatform_?fee/i,
109
+ /\btake_?rate/i,
110
+ /\bservice_?fee/i,
111
+ ], 20);
82
112
  for (const hit of hits)
83
113
  evidence.push({ type: 'snippet', value: hit.snippet, file: hit.file, line: hit.line });
84
114
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@produtype/core",
3
- "version": "0.7.0",
3
+ "version": "0.7.1",
4
4
  "description": "Deterministic CLI and library that analyzes a web application repository and reports how far it is from production-ready for the kind of product it is meant to be.",
5
5
  "license": "MIT",
6
6
  "bin": {