Skip to content

UN-4270 [FEAT] v1 scaffold, strict TypeScript and import boundary - #2380

Draft
jaseemjaskp wants to merge 2 commits into
mainfrom
UN-4270-v1-scaffold
Draft

jaseemjaskp wants to merge 2 commits into
mainfrom
UN-4270-v1-scaffold

Conversation

@jaseemjaskp

@jaseemjaskp jaseemjaskp commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

What

  • Adds frontend/src/v1/, an isolated tree for the v1 frontend. It has the folder taxonomy from the spec, a public entry (src/v1/index.ts, which v0 imports as @v1) and a placeholder for the cloud overlay.
  • Adds a strict v1 TypeScript config (src/v1/tsconfig.json).
  • Enforces the import boundary both ways:
    • v1 may import nothing outside src/v1.
    • v0 may import only the @v1 entry.
  • Bans on v1 code:
    • Biome: prop-types, antd, component .css, explicit any.
    • Guard script: the ant- class prefix, PropTypes assignments, component style files outside styles/.
  • Enforces the folder contract, e.g. components/ui/ may import only lib/ and styles/, and pages may not import other pages.
  • Adds the typecheck:v1, lint:v1 and test:v1 scripts. v0 scripts are unchanged.

Why

  • P0-T01 (UN-4270, spec) gives v1 code a place where it cannot touch v0 and v0 cannot reach into it.
  • It blocks the rest of phase P0: T02–T05 and T07–T11.

How

Rule Enforced by
v1 ↛ v0 (../, @/, src/), v0 ↛ v1 except @v1 Biome noRestrictedImports in two overrides in biome.json. This already runs in biome ci src/, pre-commit and editors
prop-types, antd, @ant-design/*, component .css, explicit any Biome, in the src/v1/** override
strict, no JS, unused locals/params, only the @v1 alias src/v1/tsconfig.json. It lives in the folder so editors pick it up; v0 tsconfig.json/jsconfig.json exclude src/v1
TypeScript-only files, style files only in styles/, folder taxonomy scripts/check-v1.mjs --files, run first by typecheck:v1
Folder import contract, PropTypes assignments, ant- class prefix scripts/check-v1.mjs --code, run by lint:v1

Why some rules live in a script rather than Biome:

  • Biome overrides replace rule options instead of merging them, so per-folder overrides would drop the v1 bans. The v1-base-rules-still-apply fixture checks that the shared rules still apply under v1.
  • allowJs: false makes tsc skip a .js file rather than fail on it. That is why the --files check runs before tsc.
  • TypeScript 7 has no JS API, so the script parses imports itself. That stays reliable because v1 specifiers can only take three forms: ./, @v1/, or a package name.
  • The ant- check is temporary. Remove it once the shadcn migration completes.

test-fixtures/v1-boundary/ holds one case per rule. For each case, the runner builds a throwaway frontend tree, overlays the case's files and runs the real package.json scripts. It uses node --test, and test-fixtures/** is excluded from vitest, so the v0 suite never collects it.

Can this PR break any existing features. If yes, please list possible items. If no, please explain why. (PS: Admins do not merge the PR without this section filled)

  • No. v0 code is untouched, and the v0 build output is byte-identical (see Notes on Testing).
  • The new Biome override for v0 only rejects imports from src/v1, and nothing in v0 imports from there today.
  • It also applies to the cloud src/plugins/ tree, which cloud CI lints with this biome.json. That is intended: cloud v0 plugins must not reach into v1 either.

Database Migrations

  • None

Env Config

  • None

Relevant Docs

  • P0-T01 spec · Phase P0
  • frontend/src/v1/README.md: the rules, the folder contract table and the scripts.

Related Issues or PRs

  • UN-4270. Sub-tasks: UN-4516, UN-4517, UN-4518, UN-4519, UN-4520, UN-4521.
  • Story UN-4258 (P0 · Foundation and guardrails).
  • Out of scope here:
    • Wiring the :v1 scripts into CI is P0-T10.
    • The v1 unit harness is P0-T08.

Dependencies Versions

  • None added

Notes on Testing

v0 no-regression, before (main @ 6e14fa7) and after:

Check Before After
vite build: sha256 of every non-sourcemap output file (239 files) 76925c7e… identical
bun run test --run 40 files / 629 passed 40 files / 629 passed
bun run typecheck pass pass
biome ci src/ exit 0, 799 warnings / 127 infos exit 0, 799 / 127

v1:

  • bun run typecheck:v1 and bun run lint:v1 pass on the empty scaffold.
  • bun run test:v1 passes 22/22: 20 rule cases, a check that every case folder is listed, and a check that no v1 or fixture file is git-ignored.

Two other fixes the fixtures turned up:

  • .gitignore: the root Python lib/ rule matched src/v1/lib/, so its files would never have been committed. The PR re-includes it, and a test guards against it happening again.
  • check-json pre-commit hook: the exclude now covers frontend/src/v1/tsconfig.json, which contains comments, matching what the hook already does for frontend/tsconfig.json.

Screenshots

N/A

Checklist

I have read and understood the Contribution Guidelines.

…N-4270)

Adds frontend/src/v1/ as an isolated tree for the v1 frontend (P0-T01):

- Folder taxonomy from the spec, a public entry (src/v1/index.ts, imported
  by v0 as `@v1`) and a cloud overlay placeholder.
- src/v1/tsconfig.json: strict, no JS, unused locals/params are errors,
  `@v1` alias only. v0's tsconfig/jsconfig exclude src/v1.
- Biome overrides for the two-way import boundary and v1 bans (no `../`,
  `@/`, prop-types, antd, component CSS; noExplicitAny).
- scripts/check-v1.mjs for what Biome cannot express: TypeScript-only
  files, the folder taxonomy and import contract, PropTypes, `ant-`.
- typecheck:v1, lint:v1 and test:v1 scripts; v0 scripts are unchanged.
- test-fixtures/v1-boundary/ proves each rule fails and passes as
  specified, run with node --test so the v0 vitest suite never sees it.
- .gitignore re-includes src/v1/lib/ (the Python `lib/` rule matched it).

v0 build output, test counts, typecheck and Biome results are unchanged.
}
// biome.json enables VCS integration with `useIgnoreFile`, which needs a
// repository root holding an ignore file.
execFileSync("git", ["init", "-q"], { cwd: dir });
let output = "";
for (const step of run) {
const command = scripts[step] ?? step;
const result = spawnSync("sh", ["-c", command], {
.filter((d) => d.isFile())
.map((d) => path.relative(FRONTEND, path.join(d.parentPath, d.name))),
);
const result = spawnSync("git", ["check-ignore", "--no-index", "--stdin"], {
…270)

check-v1.mjs:
- Scan comments with a string/template-aware tokenizer; a `/*` or `//`
  inside a string or line comment no longer hides the imports after it.
- Read template-literal specifiers, import.meta.glob and `import(..., opts)`.
- Flag specifiers that leave src/v1 (`/`, `..`, `@/`, `src/`) itself, not
  only via Biome, which skips template literals.
- Check `@import`/`url()` and `ant-` in styles/ CSS; report symlinks;
  catch built `ant-` names; treat .test/.spec .mts/.cts as test files;
  ignore .DS_Store; drop the unused --root option.

biome.json: also ban `..`, `./../**`, `/**`, `antd/**`, `prop-types/**`.
tsconfig: skipLibCheck off so v1's own .d.ts files are checked.
.gitignore: re-include lib/ at any depth under src/v1.

Fixtures: a generated matrix over every folder-contract pair, every import
form, every outside spelling, a symlink case, and cases for each new rule;
tsc cases assert error codes; output matching excludes the command text and
spawn errors fail loudly. Comment and README corrections.
@jaseemjaskp

Copy link
Copy Markdown
Contributor Author

Self-review (draft)

Four review passes (code, tests, comments, silent failures) were run against 0c5bacb57. Fixes are in 5c55a7c12.

Fixed

  • Comment stripping hid real imports. A /* inside a string ("/projects/*") or inside a // comment blanked everything up to the next */, so contract violations in between passed. check-v1.mjs now uses a tokenizer that knows about strings and template literals.
  • Imports that went unchecked:
    • template-literal specifiers (import(`@v1/...`))
    • import.meta.glob
    • import(x, opts)
    • root-absolute /src/... (this one passed Biome, check-v1 and tsc alike)
    • bare .. and ./../...
  • Banned subpaths: antd/** and prop-types/** are now banned too, not only the bare package names.
  • CSS in styles/: @import / url() targets outside v1 and ant- classes are now checked. Built ant- names (`ant-${x}`) are caught too.
  • Symlinks under v1 are now reported. Before, file symlinks were invisible to the walker.
  • skipLibCheck is off for v1, so hand-written .d.ts files under v1 are type-checked.
  • .gitignore: lib/ is now re-included at any depth under src/v1, not only at the top level.
  • Fixtures:
    • The full folder contract is tested as a generated matrix, every folder pair in both file and folder form. The expected table is written out independently of the script.
    • Every import form has its own case, and so does every "outside v1" spelling.
    • The test-file exemption now has failing cases as well as passing ones.
    • Passing cases now cover CSS in styles/ and a .tsx component.
    • tsc cases assert error codes (TS7006, TS18048, TS6133).
    • Output matching excludes the command text.
    • Spawn errors fail loudly.
    • Check that the new tests bite: run against the previous guard script and biome.json, 9 of them fail; with the fixes, 38/38 pass.
  • Docs and comments: the README now matches the code. The unused --root option is gone. Internal task IDs are replaced with Jira keys.

Not changed, by design or out of scope

  • The :v1 scripts are not in CI yet. That is P0-T10 (UN-4363). Until then CI enforces only the Biome half: the boundary and the banned imports.
  • v0 → v1 through template literals, import.meta.glob, require or CSS @import is not caught. Only Biome watches the v0 side, and it doesn't read those forms. This is low risk: it would take deliberate effort, and Vite is ESM-only.
  • test:v1 keeps --passWithNoTests until the v1 unit harness (UN-4329) adds its first test.
  • pages/* may import app/, test/ and the entry, as the spec's table says ("everything except other pages"). Worth a spec decision if pages should be stricter.

v0 regression (re-run on 5c55a7c12)

  • Build output is identical: 76925c7e….
  • Tests: 40 files, 629 passing.
  • typecheck: pass.
  • biome ci src/: 799 warnings, 127 infos (same as before).

@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
10.4% Duplication on New Code (required ≤ 3%)
B Security Rating on New Code (required ≥ A)
D Reliability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants