@multiplatform.one/config 7.11.0 → 7.15.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/README.md +35 -10
- package/lib/index.js +2 -2
- package/lib/{storybook-CGNSgSBS.js → storybook-DFdvDJ_s.js} +3 -1
- package/lib/storybook.js +1 -1
- package/lib/{vite-D6vMjPwv.js → vite-DXXr5In0.js} +167 -12
- package/lib/vite.js +3 -3
- package/lib/{workspacePublicPackages-B4FGgRYG.js → workspacePublicPackages-BuYRXxFs.js} +10 -3
- package/lint.d.ts +8 -0
- package/lint.mjs +350 -13
- package/oxlint.d.ts +2 -0
- package/oxlint.json +21 -0
- package/oxlint.mjs +168 -1
- package/package.json +8 -4
- package/spec-registry.mjs +183 -0
- package/src/lint.spec.ts +493 -1
- package/src/oxlint.spec.ts +172 -0
- package/src/oxlintPreset.spec.ts +65 -0
- package/src/publicConfig.spec.ts +272 -0
- package/src/publicConfig.ts +170 -0
- package/src/singletonDepAliases.spec.ts +52 -0
- package/src/singletonDepAliases.ts +10 -3
- package/src/spec-registry.spec.ts +107 -0
- package/src/storybook.spec.ts +2 -0
- package/src/storybook.ts +7 -0
- package/src/vite.spec.ts +58 -2
- package/src/vite.ts +53 -8
- package/types/publicConfig.d.ts +36 -0
- package/types/publicConfig.d.ts.map +1 -0
- package/types/singletonDepAliases.d.ts.map +1 -1
- package/types/storybook.d.ts.map +1 -1
- package/types/vite.d.ts +13 -4
- package/types/vite.d.ts.map +1 -1
package/README.md
CHANGED
|
@@ -58,29 +58,54 @@ Available presets: `base.json`, `build.json`, `app.json`.
|
|
|
58
58
|
|
|
59
59
|
### Oxlint
|
|
60
60
|
|
|
61
|
-
Convention rules travel with the package.
|
|
61
|
+
Convention rules travel with the package. A consuming app extends the preset
|
|
62
|
+
and needs no rules block of its own (MPO-23):
|
|
62
63
|
|
|
63
64
|
```json
|
|
64
65
|
{
|
|
65
|
-
"
|
|
66
|
+
"extends": ["./node_modules/@multiplatform.one/config/oxlint.json"]
|
|
66
67
|
}
|
|
67
68
|
```
|
|
68
69
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
70
|
+
oxlint resolves `extends` as a file path, not a package name, hence the
|
|
71
|
+
`node_modules` prefix. The preset loads the plugin, turns
|
|
72
|
+
`no-hex-literals` and `no-raw-typography` on as errors, turns
|
|
73
|
+
`no-chrome-props`, `no-raw-geometry` and `no-child-margin` on as warnings
|
|
74
|
+
while their burndowns run, and exempts specs and `tests/` trees, which assert
|
|
75
|
+
computed colours, from all but `no-raw-typography`. A project that wants its
|
|
76
|
+
own levels keeps the older one-line form,
|
|
77
|
+
`{ "jsPlugins": ["@multiplatform.one/config/oxlint"] }`, and writes its own
|
|
78
|
+
rules block (mpo's own `oxlintrc.json` turns `no-hex-literals` on for
|
|
79
|
+
`apps/**`, `packages/**` and `features/**`, and off for specs and `tests/`
|
|
80
|
+
trees). Palette modules (`themes/base.ts`, `themes/accent.ts`,
|
|
81
|
+
`*palette*`) are exempt. Comments are not visited, so a JSDoc `#025` is not
|
|
82
|
+
a hit. A file no theme token reaches opts out with a `// hex-escape: <reason>`
|
|
83
|
+
line comment; `lint` fails that comment unless the spec table
|
|
84
|
+
`## Colour-literal escapes` has its file and exact reason, and fails a row
|
|
85
|
+
whose comment is gone (MPO-326).
|
|
75
86
|
|
|
76
87
|
`no-chrome-props` and `no-raw-geometry` ship in the same plugin (MPO-17).
|
|
77
88
|
Enable them the same way when you start that burndown. Drawing-file
|
|
78
89
|
exceptions come from the spec table `## Drawing files`, not from the code.
|
|
79
90
|
|
|
91
|
+
`no-child-margin` (MPO-23, `00` L9a) fails a non-zero `margin*` prop, long
|
|
92
|
+
or shorthand, on any element nested inside another element's JSX: the parent
|
|
93
|
+
owns the gap. `0` is always legal, the outermost element a file renders is
|
|
94
|
+
left alone, and slots come from the spec table `## Slot margins`. mpo's own
|
|
95
|
+
`oxlintrc.json` runs it as an error over `apps/`, `features/`, `packages/` and
|
|
96
|
+
`public/`, off for specs and `tests/` trees and for a named burndown list: the
|
|
97
|
+
73 files that carried 133 hits when it was switched on. The list may only
|
|
98
|
+
shrink; `scripts/child-margin-ratchet.spec.mjs` fails if it grows, names a
|
|
99
|
+
pattern instead of a file, or keeps a file that no longer violates.
|
|
100
|
+
|
|
80
101
|
### Lint (node-script checks)
|
|
81
102
|
|
|
82
|
-
CSS-in-apps, features-twin, silent token no-ops,
|
|
83
|
-
pilot
|
|
103
|
+
CSS-in-apps, features-twin, silent token no-ops, the LC-65 size-recipe
|
|
104
|
+
pilot, and the size-recipe escape registry run through
|
|
105
|
+
`runConventionChecks({ roots })`. Every `sizeRecipeEscape` site, and every
|
|
106
|
+
`size-recipe-escape:` comment, must be a row in the spec table
|
|
107
|
+
`## Size-recipe escapes` by file and exact reason, and a row whose site is
|
|
108
|
+
gone fails too (MPO-23, `00` L8 E8):
|
|
84
109
|
|
|
85
110
|
```ts
|
|
86
111
|
import { runConventionChecks } from "@multiplatform.one/config/lint";
|
package/lib/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { t as createViteConfig } from "./vite-
|
|
2
|
-
import { t as createStorybookViteConfig } from "./storybook-
|
|
1
|
+
import { t as createViteConfig } from "./vite-DXXr5In0.js";
|
|
2
|
+
import { t as createStorybookViteConfig } from "./storybook-DFdvDJ_s.js";
|
|
3
3
|
import { n as tamaguiWorkspacePathsFile, t as ensureTamaguiWorkspacePaths } from "./tamaguiWorkspacePaths-ZIcqybtn.js";
|
|
4
4
|
import { createVitestConfig } from "./vitest.js";
|
|
5
5
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as withSingletonDepAliases, r as resolvePackageMainSource, t as discoverPublicPackageRoots } from "./workspacePublicPackages-
|
|
1
|
+
import { i as withSingletonDepAliases, r as resolvePackageMainSource, t as discoverPublicPackageRoots } from "./workspacePublicPackages-BuYRXxFs.js";
|
|
2
2
|
import { t as ensureTamaguiWorkspacePaths } from "./tamaguiWorkspacePaths-ZIcqybtn.js";
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
4
|
import fs from "node:fs";
|
|
@@ -131,6 +131,8 @@ function createStorybookViteConfig(options = {}) {
|
|
|
131
131
|
"@tamagui/web",
|
|
132
132
|
"@tamagui/helpers-icon",
|
|
133
133
|
"tamagui",
|
|
134
|
+
"@tamagui/animations-css",
|
|
135
|
+
"@tamagui/react-native-svg",
|
|
134
136
|
"@tamagui/colors",
|
|
135
137
|
"@tamagui/config",
|
|
136
138
|
"@tamagui/config/v5",
|
package/lib/storybook.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import { i as withSingletonDepAliases, t as discoverPublicPackageRoots } from "./workspacePublicPackages-
|
|
1
|
+
import { i as withSingletonDepAliases, t as discoverPublicPackageRoots } from "./workspacePublicPackages-BuYRXxFs.js";
|
|
2
2
|
import { t as ensureTamaguiWorkspacePaths } from "./tamaguiWorkspacePaths-ZIcqybtn.js";
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
4
|
import fs from "node:fs";
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import { spawnSync } from "node:child_process";
|
|
7
|
-
import { tamaguiPlugin } from "@tamagui/vite-plugin";
|
|
8
7
|
import dotenv from "dotenv";
|
|
8
|
+
import { transformWithOxc } from "vite";
|
|
9
|
+
import { tamaguiPlugin } from "@tamagui/vite-plugin";
|
|
9
10
|
import createExternal from "vite-plugin-external";
|
|
10
11
|
import i18nextLoader from "vite-plugin-i18next-loader";
|
|
11
12
|
|
|
@@ -54,6 +55,148 @@ function lookupProjectRoot() {
|
|
|
54
55
|
}
|
|
55
56
|
}
|
|
56
57
|
|
|
58
|
+
//#endregion
|
|
59
|
+
//#region src/publicConfig.ts
|
|
60
|
+
const bakedConfigEnvKey = "VITE_MP_CONFIG";
|
|
61
|
+
const publicConfigKeysEnvKey = "VITE_MP_PUBLIC_CONFIG_KEYS";
|
|
62
|
+
/**
|
|
63
|
+
* The `public` key names of a config.json, read rather than imported: a
|
|
64
|
+
* static import puts the file on Vite's configFileDependencies, and every
|
|
65
|
+
* edit then restarts the dev server, re-optimizes deps and 504s each open tab
|
|
66
|
+
* (MPO-247). A read keeps it off that list.
|
|
67
|
+
*/
|
|
68
|
+
function readPublicConfigKeys(file) {
|
|
69
|
+
const parsed = JSON.parse(fs.readFileSync(file, "utf-8"));
|
|
70
|
+
const keys = parsed && typeof parsed === "object" ? parsed.public : [];
|
|
71
|
+
if (!Array.isArray(keys)) return [];
|
|
72
|
+
return keys.filter((key) => typeof key === "string" && key.length > 0);
|
|
73
|
+
}
|
|
74
|
+
function mergePublicConfigKeys(...lists) {
|
|
75
|
+
return [...new Set(lists.flat())];
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Put the bake on process.env: the values resolved from the environment under
|
|
79
|
+
* VITE_MP_CONFIG and the key NAMES under VITE_MP_PUBLIC_CONFIG_KEYS. Names,
|
|
80
|
+
* never a value, is what lets the SSR node process resolve them from its own
|
|
81
|
+
* environment at request time (@multiplatform.one/platform runtimeConfig.ts).
|
|
82
|
+
*/
|
|
83
|
+
function bakePublicConfig(keys) {
|
|
84
|
+
process.env[bakedConfigEnvKey] = JSON.stringify(resolveConfig(keys));
|
|
85
|
+
process.env[publicConfigKeysEnvKey] = JSON.stringify(keys);
|
|
86
|
+
}
|
|
87
|
+
const bakedExpression = /\bprocess\??\.env\??\.(?:VITE_MP_CONFIG|VITE_MP_PUBLIC_CONFIG_KEYS)\b/;
|
|
88
|
+
const nonScriptRequest = /\.(?:json|css|html)(?:$|\?)/;
|
|
89
|
+
const nodeModulesPath = /[\\/]node_modules[\\/]/;
|
|
90
|
+
/**
|
|
91
|
+
* The same replacement vite:define makes, done through oxc so only real
|
|
92
|
+
* `process.env.<KEY>` reads change: a string, an assignment target or a
|
|
93
|
+
* `globalThis.process.env.<KEY>` is left as written.
|
|
94
|
+
*/
|
|
95
|
+
function bakedDefine() {
|
|
96
|
+
return Object.fromEntries([bakedConfigEnvKey, publicConfigKeysEnvKey].map((key) => [`process.env.${key}`, JSON.stringify(process.env[key] ?? "")]));
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* The browser caches node_modules files and optimized deps as immutable under
|
|
100
|
+
* a ?v= hash that no define value feeds, so a value inlined there would
|
|
101
|
+
* outlive every reload and restart. Those keep reading the defines vite
|
|
102
|
+
* injects through /@vite/env instead.
|
|
103
|
+
*/
|
|
104
|
+
function browserCached(environment, id) {
|
|
105
|
+
if (!environment || environment.config.consumer === "server") return false;
|
|
106
|
+
if (nodeModulesPath.test(id)) return true;
|
|
107
|
+
return "depsOptimizer" in environment && !!environment.depsOptimizer?.isOptimizedDepFile(id);
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Dev-server half of `publicConfigFile`. vite:define freezes its replacement
|
|
111
|
+
* table per environment when the server starts, so this plugin inlines the
|
|
112
|
+
* two baked expressions itself (it runs ahead of vite:define), remembers the
|
|
113
|
+
* modules that carried them, and when config.json changes rebakes,
|
|
114
|
+
* invalidates those modules and reloads every environment. The server never
|
|
115
|
+
* restarts, so the dep optimizer never runs again.
|
|
116
|
+
*/
|
|
117
|
+
function publicConfigPlugin(options) {
|
|
118
|
+
const file = path.resolve(options.file);
|
|
119
|
+
const envFile = path.resolve(options.projectRoot, ".env");
|
|
120
|
+
const inlineKeys = options.keys ?? [];
|
|
121
|
+
const bakedModules = /* @__PURE__ */ new Map();
|
|
122
|
+
function readKeys() {
|
|
123
|
+
return mergePublicConfigKeys(inlineKeys, readPublicConfigKeys(file));
|
|
124
|
+
}
|
|
125
|
+
function bake(next) {
|
|
126
|
+
dotenv.config({
|
|
127
|
+
path: envFile,
|
|
128
|
+
quiet: true
|
|
129
|
+
});
|
|
130
|
+
bakePublicConfig(next);
|
|
131
|
+
}
|
|
132
|
+
let keys = readKeys();
|
|
133
|
+
bake(keys);
|
|
134
|
+
function refresh(server) {
|
|
135
|
+
const label = path.relative(process.cwd(), file);
|
|
136
|
+
let next;
|
|
137
|
+
try {
|
|
138
|
+
next = readKeys();
|
|
139
|
+
} catch (err) {
|
|
140
|
+
server.config.logger.warn(`${label}: ${err.message}; keeping the previous public keys`, { timestamp: true });
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
if (next.length === keys.length && next.every((key, i) => key === keys[i])) return;
|
|
144
|
+
keys = next;
|
|
145
|
+
bake(keys);
|
|
146
|
+
for (const [name, ids] of bakedModules) {
|
|
147
|
+
const environment = server.environments[name];
|
|
148
|
+
if (!environment) continue;
|
|
149
|
+
for (const id of ids) {
|
|
150
|
+
const mod = environment.moduleGraph.getModuleById(id);
|
|
151
|
+
if (mod) environment.moduleGraph.invalidateModule(mod);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
for (const environment of Object.values(server.environments)) environment.hot.send({
|
|
155
|
+
type: "full-reload",
|
|
156
|
+
path: "*"
|
|
157
|
+
});
|
|
158
|
+
server.config.logger.info(`${label} changed, reloading with public keys ${keys.join(", ")}`, { timestamp: true });
|
|
159
|
+
}
|
|
160
|
+
return {
|
|
161
|
+
name: "multiplatform-public-config",
|
|
162
|
+
apply: "serve",
|
|
163
|
+
async transform(code, id) {
|
|
164
|
+
if (nonScriptRequest.test(id) || !bakedExpression.test(code)) return;
|
|
165
|
+
if (browserCached(this.environment, id)) return;
|
|
166
|
+
let result;
|
|
167
|
+
try {
|
|
168
|
+
result = await transformWithOxc(code, id, {
|
|
169
|
+
lang: "js",
|
|
170
|
+
sourceType: "module",
|
|
171
|
+
define: bakedDefine(),
|
|
172
|
+
tsconfig: false
|
|
173
|
+
});
|
|
174
|
+
} catch {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
const name = this.environment?.name ?? "client";
|
|
178
|
+
let ids = bakedModules.get(name);
|
|
179
|
+
if (!ids) {
|
|
180
|
+
ids = /* @__PURE__ */ new Set();
|
|
181
|
+
bakedModules.set(name, ids);
|
|
182
|
+
}
|
|
183
|
+
ids.add(id);
|
|
184
|
+
return {
|
|
185
|
+
code: result.code,
|
|
186
|
+
map: result.map
|
|
187
|
+
};
|
|
188
|
+
},
|
|
189
|
+
configureServer(server) {
|
|
190
|
+
server.watcher.add(file);
|
|
191
|
+
const onChange = (changed) => {
|
|
192
|
+
if (path.resolve(changed) === file) refresh(server);
|
|
193
|
+
};
|
|
194
|
+
server.watcher.on("change", onChange);
|
|
195
|
+
server.watcher.on("add", onChange);
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
|
|
57
200
|
//#endregion
|
|
58
201
|
//#region src/vite.ts
|
|
59
202
|
/**
|
|
@@ -66,11 +209,11 @@ function lookupProjectRoot() {
|
|
|
66
209
|
* @example
|
|
67
210
|
* ```ts
|
|
68
211
|
* // apps/one/vite.config.ts
|
|
212
|
+
* import path from "node:path";
|
|
69
213
|
* import { createViteConfig } from "@multiplatform.one/config/vite";
|
|
70
|
-
* import { public as publicConfigKeys } from "../../features/config.json";
|
|
71
214
|
*
|
|
72
215
|
* export default createViteConfig({
|
|
73
|
-
*
|
|
216
|
+
* publicConfigFile: path.resolve(__dirname, "../../packages/config/config.json"),
|
|
74
217
|
* one: { web: { deploy: "node", defaultRenderMode: "ssr" } },
|
|
75
218
|
* tamagui: { config: "./config/tamagui.config.ts" },
|
|
76
219
|
* i18n: { paths: ["../../features/i18n"] },
|
|
@@ -79,15 +222,18 @@ function lookupProjectRoot() {
|
|
|
79
222
|
*/
|
|
80
223
|
function createViteConfig(options = {}) {
|
|
81
224
|
ensureTamaguiWorkspacePaths();
|
|
82
|
-
const { projectRoot: _projectRoot, publicConfigKeys = [], tamagui = true, i18n = false, one = false, ssr, server, plugins: extraPlugins = [], externalReactRouter, ssrDeps, ssrEntries, ssrCjsExternal, nativeFixes } = options;
|
|
225
|
+
const { projectRoot: _projectRoot, publicConfigKeys: inlinePublicConfigKeys = [], publicConfigFile, tamagui = true, i18n = false, one = false, ssr, server, plugins: extraPlugins = [], externalReactRouter, ssrDeps, ssrEntries, ssrCjsExternal, nativeFixes } = options;
|
|
83
226
|
const projectRoot = _projectRoot || findProjectRoot();
|
|
227
|
+
const publicConfigKeys = publicConfigFile ? mergePublicConfigKeys(inlinePublicConfigKeys, readPublicConfigKeys(publicConfigFile)) : inlinePublicConfigKeys;
|
|
84
228
|
dotenv.config({ path: path.resolve(projectRoot, ".env") });
|
|
85
|
-
if (publicConfigKeys.length > 0)
|
|
86
|
-
process.env.VITE_MP_CONFIG = JSON.stringify(resolveConfig(publicConfigKeys));
|
|
87
|
-
process.env.VITE_MP_PUBLIC_CONFIG_KEYS = JSON.stringify(publicConfigKeys);
|
|
88
|
-
}
|
|
229
|
+
if (publicConfigKeys.length > 0) bakePublicConfig(publicConfigKeys);
|
|
89
230
|
const vitePlugins = [];
|
|
90
231
|
vitePlugins.push(preferBuiltWorkspaceEntryPlugin());
|
|
232
|
+
if (publicConfigFile) vitePlugins.push(publicConfigPlugin({
|
|
233
|
+
file: publicConfigFile,
|
|
234
|
+
projectRoot,
|
|
235
|
+
keys: inlinePublicConfigKeys
|
|
236
|
+
}));
|
|
91
237
|
if (one) {
|
|
92
238
|
vitePlugins.push(ssrReactNativeAliasPlugin());
|
|
93
239
|
vitePlugins.push(clientBrokenEsmPlugin());
|
|
@@ -257,7 +403,10 @@ function clientBrokenEsmPlugin() {
|
|
|
257
403
|
"react-is",
|
|
258
404
|
"fast-deep-equal",
|
|
259
405
|
"color",
|
|
260
|
-
"query-string"
|
|
406
|
+
"query-string",
|
|
407
|
+
"react/jsx-runtime",
|
|
408
|
+
"react/jsx-dev-runtime",
|
|
409
|
+
"tamagui"
|
|
261
410
|
];
|
|
262
411
|
const include = clientEnv.optimizeDeps.include ?? [];
|
|
263
412
|
for (const dep of extras) if (!include.includes(dep)) include.push(dep);
|
|
@@ -482,11 +631,17 @@ function ssrCjsExternalFixPlugin(extras) {
|
|
|
482
631
|
configResolved(config) {
|
|
483
632
|
const external = config.ssr.external ?? [];
|
|
484
633
|
if (!Array.isArray(external)) return;
|
|
485
|
-
for (const e of extras)
|
|
634
|
+
for (const e of extras) {
|
|
635
|
+
if (config.command === "build" && requiresReact(e)) continue;
|
|
636
|
+
if (!external.includes(e)) external.push(e);
|
|
637
|
+
}
|
|
486
638
|
config.ssr.external = external;
|
|
487
639
|
}
|
|
488
640
|
};
|
|
489
641
|
}
|
|
642
|
+
function requiresReact(id) {
|
|
643
|
+
return id === "use-sync-external-store" || id.startsWith("use-sync-external-store/");
|
|
644
|
+
}
|
|
490
645
|
/**
|
|
491
646
|
* Restore Object.prototype methods shadowed by hoisted globals on NATIVE.
|
|
492
647
|
*
|
|
@@ -626,4 +781,4 @@ function preferBuiltWorkspaceEntryPlugin() {
|
|
|
626
781
|
}
|
|
627
782
|
|
|
628
783
|
//#endregion
|
|
629
|
-
export { createViteConfig as t };
|
|
784
|
+
export { publicConfigPlugin as n, readPublicConfigKeys as r, createViteConfig as t };
|
package/lib/vite.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as createViteConfig } from "./vite-
|
|
2
|
-
import { n as publicPackageViteSourceAliases, t as discoverPublicPackageRoots } from "./workspacePublicPackages-
|
|
1
|
+
import { n as publicConfigPlugin, r as readPublicConfigKeys, t as createViteConfig } from "./vite-DXXr5In0.js";
|
|
2
|
+
import { n as publicPackageViteSourceAliases, t as discoverPublicPackageRoots } from "./workspacePublicPackages-BuYRXxFs.js";
|
|
3
3
|
|
|
4
|
-
export { createViteConfig, discoverPublicPackageRoots, publicPackageViteSourceAliases };
|
|
4
|
+
export { createViteConfig, discoverPublicPackageRoots, publicConfigPlugin, publicPackageViteSourceAliases, readPublicConfigKeys };
|
|
@@ -75,9 +75,16 @@ import path from "node:path";
|
|
|
75
75
|
* clause and not the whole rule: `@tanstack/db` references the hook nowhere
|
|
76
76
|
* and is pinned anyway, for the collection registry it holds at module scope.
|
|
77
77
|
*
|
|
78
|
-
* `@tanstack/react-query` references the hook in 25 shipped files
|
|
79
|
-
* listed.
|
|
80
|
-
*
|
|
78
|
+
* MPO-290. `@tanstack/react-query` references the hook in 25 shipped files
|
|
79
|
+
* and is deliberately NOT listed. It passes the grep, but a pin only earns its
|
|
80
|
+
* place where a second record can exist, and here none does. Measured at
|
|
81
|
+
* 5.100.7 on 0af30157c: seven workspace packages declare it and the lockfile
|
|
82
|
+
* resolves all seven to one snapshot, `5.100.7(react@19.2.5)`. The hoisted
|
|
83
|
+
* install holds one physical copy. So does the isolated layout an unset
|
|
84
|
+
* NPM_AUTH_TOKEN produced while .npmrc held the linker keys, rebuilt by
|
|
85
|
+
* stripping them from pnpm-workspace.yaml: fourteen links, one realpath. The
|
|
86
|
+
* spec re-checks both halves, so a second version or peer set fails there
|
|
87
|
+
* before it splits an app.
|
|
81
88
|
*/
|
|
82
89
|
const CONTEXT_SINGLETONS = [
|
|
83
90
|
"react-cookie",
|
package/lint.d.ts
CHANGED
|
@@ -19,3 +19,11 @@ export function resolveRoots(roots?: ConventionRoots): {
|
|
|
19
19
|
};
|
|
20
20
|
|
|
21
21
|
export function runConventionChecks(options?: RunConventionChecksOptions): number;
|
|
22
|
+
|
|
23
|
+
export type SizeRecipeEscapeSite = {
|
|
24
|
+
line: number;
|
|
25
|
+
form: "prop" | "call" | "comment";
|
|
26
|
+
reason: string | undefined;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export function findSizeRecipeEscapes(src: string): SizeRecipeEscapeSite[];
|