@erclx/canon 4.62.0 → 4.62.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.
package/package.json
CHANGED
|
@@ -98,14 +98,18 @@ function citationPattern(folder: string): RegExp {
|
|
|
98
98
|
)
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
-
|
|
102
|
-
const REWRITES: readonly {
|
|
101
|
+
interface Rewrite {
|
|
103
102
|
readonly pattern: RegExp
|
|
104
103
|
readonly folder: string
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** One rewrite per folder, paired with its citation pattern. */
|
|
107
|
+
function buildRewrites(folders: readonly string[]): readonly Rewrite[] {
|
|
108
|
+
return folders.map((folder) => ({
|
|
109
|
+
pattern: citationPattern(folder),
|
|
110
|
+
folder,
|
|
111
|
+
}))
|
|
112
|
+
}
|
|
109
113
|
|
|
110
114
|
/**
|
|
111
115
|
* Marks a line naming a promoted folder's old path on purpose, the same
|
|
@@ -125,40 +129,43 @@ function isKept(lines: readonly string[], index: number): boolean {
|
|
|
125
129
|
return above >= 0 && (lines[above]?.includes(KEEP_MARKER) ?? false)
|
|
126
130
|
}
|
|
127
131
|
|
|
128
|
-
function rewriteLine(line: string): string {
|
|
129
|
-
return
|
|
132
|
+
function rewriteLine(line: string, rewrites: readonly Rewrite[]): string {
|
|
133
|
+
return rewrites.reduce(
|
|
130
134
|
(current, { pattern, folder }) =>
|
|
131
135
|
current.replace(pattern, `.canon/review/evidence/${folder}`),
|
|
132
136
|
line,
|
|
133
137
|
)
|
|
134
138
|
}
|
|
135
139
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
* citation was spelled. A file naming no promoted folder returns
|
|
140
|
-
* byte-identical, and a marked line is returned unchanged.
|
|
141
|
-
*/
|
|
142
|
-
export function rewriteScratchEvidence(text: string): string {
|
|
143
|
-
const lines = text.split('\n')
|
|
144
|
-
return lines
|
|
145
|
-
.map((line, index) => (isKept(lines, index) ? line : rewriteLine(line)))
|
|
146
|
-
.join('\n')
|
|
140
|
+
interface RewriteOutcome {
|
|
141
|
+
readonly text: string
|
|
142
|
+
readonly count: number
|
|
147
143
|
}
|
|
148
144
|
|
|
149
|
-
/**
|
|
150
|
-
|
|
145
|
+
/**
|
|
146
|
+
* Rewrites every unmarked citation of a folder `rewrites` covers into its
|
|
147
|
+
* destination under `.canon/review/evidence/`, absolute regardless of how the
|
|
148
|
+
* source citation was spelled, counting each as it goes. A file naming no
|
|
149
|
+
* such folder returns byte-identical with a count of zero, and a marked line
|
|
150
|
+
* is returned unchanged and uncounted.
|
|
151
|
+
*/
|
|
152
|
+
function applyRewrites(
|
|
153
|
+
text: string,
|
|
154
|
+
rewrites: readonly Rewrite[],
|
|
155
|
+
): RewriteOutcome {
|
|
151
156
|
const lines = text.split('\n')
|
|
152
157
|
let count = 0
|
|
153
158
|
|
|
154
|
-
|
|
155
|
-
if (isKept(lines, index))
|
|
156
|
-
|
|
159
|
+
const rewritten = lines.map((line, index) => {
|
|
160
|
+
if (isKept(lines, index)) return line
|
|
161
|
+
|
|
162
|
+
for (const { pattern } of rewrites) {
|
|
157
163
|
count += [...line.matchAll(pattern)].length
|
|
158
164
|
}
|
|
159
|
-
|
|
165
|
+
return rewriteLine(line, rewrites)
|
|
166
|
+
})
|
|
160
167
|
|
|
161
|
-
return count
|
|
168
|
+
return { text: rewritten.join('\n'), count }
|
|
162
169
|
}
|
|
163
170
|
|
|
164
171
|
/** The files under every `BACKED_FOLDERS` entry, archives included. */
|
|
@@ -261,17 +268,17 @@ export function planScratchEvidence(
|
|
|
261
268
|
sources: readonly ScratchEvidenceSource[],
|
|
262
269
|
): ScratchEvidencePlan {
|
|
263
270
|
const { moves, collisions } = planFolderMoves(root)
|
|
271
|
+
const folders = PROMOTED_FOLDERS.filter(
|
|
272
|
+
(folder) => !collisions.includes(destinationPath(root, folder)),
|
|
273
|
+
)
|
|
274
|
+
const rewrites = buildRewrites(folders)
|
|
264
275
|
const entries: CitationEntry[] = []
|
|
265
276
|
|
|
266
277
|
for (const source of sources) {
|
|
267
|
-
const
|
|
268
|
-
if (
|
|
269
|
-
|
|
270
|
-
entries.push({
|
|
271
|
-
path: source.path,
|
|
272
|
-
text: rewriteScratchEvidence(source.text),
|
|
273
|
-
rewritten,
|
|
274
|
-
})
|
|
278
|
+
const { text, count } = applyRewrites(source.text, rewrites)
|
|
279
|
+
if (count === 0) continue
|
|
280
|
+
|
|
281
|
+
entries.push({ path: source.path, text, rewritten: count })
|
|
275
282
|
}
|
|
276
283
|
|
|
277
284
|
return {
|
|
@@ -26,7 +26,7 @@ export default defineConfig([
|
|
|
26
26
|
...tseslint.configs.recommended,
|
|
27
27
|
...astro.configs.recommended,
|
|
28
28
|
{
|
|
29
|
-
files: ['**/*.{ts,tsx,js,jsx}'],
|
|
29
|
+
files: ['**/*.{ts,tsx,js,jsx,astro}'],
|
|
30
30
|
plugins: {
|
|
31
31
|
'simple-import-sort': simpleImportSort,
|
|
32
32
|
'check-file': checkFile,
|
|
@@ -21,7 +21,7 @@ The astro stack covers Astro + TypeScript projects: content sites, marketing sit
|
|
|
21
21
|
- `vitest.config.ts`: uses `getViteConfig` from `astro/config` (not `mergeConfig`). jsdom, globals, setup file, `passWithNoTests: true`, v8 coverage, `**/*.astro` in coverage excludes.
|
|
22
22
|
- `playwright.config.ts`: all browsers, `webServer` runs `bun run build && bun run preview` on port `4321` plus `WORKTREE_PORT_OFFSET`, `reuseExistingServer: false`. Astro's dev/prod gap is wide (MDX, island hydration, asset optimization), so E2E always tests the built `dist/`. `DIST_PREBUILT` set in the environment drops the `build` half, running `bun run preview` alone against a `dist/` a prior CI job already produced.
|
|
23
23
|
- `tsconfig.json`: extends `astro/tsconfigs/strict`, adds `skipLibCheck`, `vitest/globals` and `@testing-library/jest-dom` in types, `@/` paths.
|
|
24
|
-
- `eslint.config.js`: overrides the web layer. Adds `eslint-plugin-astro` (`.astro` parser via `astro-eslint-parser`). React-hooks scoped to `.jsx`/`.tsx` only (`.astro` is not React). `
|
|
24
|
+
- `eslint.config.js`: overrides the web layer. Adds `eslint-plugin-astro` (`.astro` parser via `astro-eslint-parser`). React-hooks scoped to `.jsx`/`.tsx` only (`.astro` is not React). The shared block's `files` selector includes `.astro`, so `check-file/filename-naming-convention` reaches `.ts`, `.tsx`, and `.astro` under `KEBAB_CASE`, overriding Astro's own PascalCase component convention deliberately, on the ground that a component's name in markup comes from the import binding rather than the filename. `.js` and `.jsx` stay out of the rule's own pattern, matching `web` and `nextjs`. `check-file/folder-naming-convention`'s `src/**/!(__tests__|pages)` pattern reaches no folder under a real ESLint run, `.astro`-only or otherwise. See `.claude/context/tooling.md` for the measurement.
|
|
25
25
|
|
|
26
26
|
## Typecheck
|
|
27
27
|
|