Skip to content

Commit

Permalink
Merge pull request #18 from chaqchase/feat/better-support-improvements
Browse files Browse the repository at this point in the history
better support and improvements
  • Loading branch information
chaqchase authored Jan 7, 2025
2 parents aacb7bc + 9f120e1 commit bd2a9e0
Show file tree
Hide file tree
Showing 19 changed files with 2,958 additions and 2,729 deletions.
6 changes: 3 additions & 3 deletions .changeset/config.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
{
"$schema": "https://unpkg.com/@changesets/config@3.0.0/schema.json",
"$schema": "https://unpkg.com/@changesets/config@2.3.0/schema.json",
"changelog": "@changesets/cli/changelog",
"commit": false,
"fixed": [],
"linked": [],
"access": "restricted",
"access": "public",
"baseBranch": "main",
"updateInternalDependencies": "patch",
"ignore": []
}
}
30 changes: 16 additions & 14 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,27 @@ on:

jobs:
test:
name: Test Node.js ${{ matrix.node-version }} on ${{ matrix.os }}

strategy:
matrix:
os: [ubuntu-latest]
node-version: [18.x]

runs-on: ${{ matrix.os }}
name: Test and Lint
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- uses: pnpm/action-setup@v2.2.2
- uses: actions/checkout@v3
- uses: pnpm/action-setup@v2
with:
version: 6.34.0
- uses: actions/setup-node@v2
version: 8
- uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
node-version: 18
cache: 'pnpm'

- name: Install Dependencies
run: pnpm install
run: pnpm install --frozen-lockfile

- name: Run Linter
run: pnpm lint

- name: Run Tests
run: pnpm test

- name: Build
run: pnpm build
27 changes: 16 additions & 11 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,27 +13,32 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout Repo
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
fetch-depth: 0

- name: Setup Node.js 20.x
uses: actions/setup-node@v2
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: 20.x
node-version: 18

- name: Setup pnpm
run: npm install -g pnpm
uses: pnpm/action-setup@v2
with:
version: 8

- name: Install Dependencies
run: pnpm i
run: pnpm install --frozen-lockfile

- name: Create Release PR or Publish Packages
- name: Create Release Pull Request or Publish to npm
id: changesets
uses: changesets/action@v1
with:
publish: pnpm release
version: pnpm version
commit: 'chore: update package versions'
title: 'chore: update package versions'
publish: pnpm run release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

- name: Send a Slack notification if a publish happens
if: steps.changesets.outputs.published == 'true'
run: my-slack-bot send-notification --message "A new version of ${GITHUB_REPOSITORY} was published!"
60 changes: 60 additions & 0 deletions __tests__/codegen.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import fs from 'fs/promises';
import { generateDeclarations, generateLinkFunction } from '../src/codegen';
import { getRoutesMap } from '../src/utils';

jest.mock('fs/promises');
jest.mock('../src/utils');

describe('codegen', () => {
const mockAppDir = '/mock/app';
const mockDeclarationPath = '/mock/declarations.d.ts';
const mockUtilsPath = '/mock/utils.ts';

beforeEach(() => {
jest.resetAllMocks();
});

describe('generateDeclarations', () => {
it('should generate declarations correctly', async () => {
const mockRoutesMap = {
'/': { path: '/', params: {}, isDynamic: false },
'/blog/[slug]': {
path: '/blog/[slug]',
params: { slug: '' },
isDynamic: true,
},
};

(getRoutesMap as jest.Mock).mockResolvedValue(mockRoutesMap);

await generateDeclarations(mockAppDir, mockDeclarationPath);

expect(fs.writeFile).toHaveBeenCalledWith(
mockDeclarationPath,
expect.stringContaining('const routes ='),
);
});
});

describe('generateLinkFunction', () => {
it('should generate link function correctly', async () => {
const mockRoutesMap = {
'/': { path: '/', params: {}, isDynamic: false },
'/blog/[slug]': {
path: '/blog/[slug]',
params: { slug: '' },
isDynamic: true,
},
};

(getRoutesMap as jest.Mock).mockResolvedValue(mockRoutesMap);

await generateLinkFunction(mockAppDir, mockUtilsPath);

expect(fs.writeFile).toHaveBeenCalledWith(
mockUtilsPath,
expect.stringContaining('const link$ ='),
);
});
});
});
3 changes: 3 additions & 0 deletions __tests__/mock-app/about/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function About() {
return <h1>About</h1>;
}
3 changes: 3 additions & 0 deletions __tests__/mock-app/blog/[slug]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function BlogPost({ params }: { params: { slug: string } }) {
return <h1>Blog Post: {params.slug}</h1>;
}
3 changes: 3 additions & 0 deletions __tests__/mock-app/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function Home() {
return <h1>Home</h1>;
}
3 changes: 3 additions & 0 deletions __tests__/mock-app/products/[...categories]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function Products({ params }: { params: { categories: string[] } }) {
return <h1>Products: {params.categories.join(', ')}</h1>;
}
3 changes: 3 additions & 0 deletions __tests__/mock-app/settings/[[...sections]]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function Settings({ params }: { params: { sections?: string[] } }) {
return <h1>Settings: {params.sections?.join(', ') || 'General'}</h1>;
}
85 changes: 85 additions & 0 deletions __tests__/utils.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import path from 'path';
import {
cleanPath,
isValidPath,
isDynamicPath,
isCatchAllRoute,
isOptionalCatchAllRoute,
generateRoutes,
} from '../src/utils';

describe('utils', () => {
describe('cleanPath', () => {
it('should clean the path correctly', () => {
const input = '/app/(auth)/login/page.tsx';
const expected = '/login';
expect(cleanPath(input, '/app')).toBe(expected);
});
});

describe('isValidPath', () => {
it('should return true for valid paths', () => {
expect(isValidPath('validPath')).toBe(true);
});

it('should return false for paths starting with underscore', () => {
expect(isValidPath('_invalidPath')).toBe(false);
});

it('should return false for paths starting with dot', () => {
expect(isValidPath('.invalidPath')).toBe(false);
});
});

describe('isDynamicPath', () => {
it('should return true for dynamic paths', () => {
expect(isDynamicPath('[id]')).toBe(true);
});

it('should return false for static paths', () => {
expect(isDynamicPath('static')).toBe(false);
});
});

describe('isCatchAllRoute', () => {
it('should return true for catch-all routes', () => {
expect(isCatchAllRoute('[...slug]')).toBe(true);
});

it('should return false for non-catch-all routes', () => {
expect(isCatchAllRoute('[id]')).toBe(false);
});
});

describe('isOptionalCatchAllRoute', () => {
it('should return true for optional catch-all routes', () => {
expect(isOptionalCatchAllRoute('[[...slug]]')).toBe(true);
});

it('should return false for non-optional catch-all routes', () => {
expect(isOptionalCatchAllRoute('[...slug]')).toBe(false);
});
});

describe('generateRoutes', () => {
it('should generate routes correctly', async () => {
const mockAppDir = path.join(__dirname, 'mock-app');
const routes = await generateRoutes(mockAppDir);

expect(routes).toEqual(
expect.arrayContaining([
expect.objectContaining({ path: '/about' }),
expect.objectContaining({ path: '/blog/[slug]', isDynamic: true }),
expect.objectContaining({
path: '/products/[...categories]',
isCatchAll: true,
}),
expect.objectContaining({
path: '/settings/[[...sections]]',
isOptionalCatchAll: true,
}),
]),
);
});
});
});
15 changes: 15 additions & 0 deletions jest.config.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
roots: ['<rootDir>/src', '<rootDir>/__tests__'],
testMatch: ['**/__tests__/**/*.ts', '**/?(*.)+(spec|test).ts'],
moduleFileExtensions: ['ts', 'js', 'json', 'node'],
extensionsToTreatAsEsm: ['.ts'],
moduleNameMapper: {
'^(\\.{1,2}/.*)\\.js$': '$1',
},
transform: {
'^.+\\.tsx?$': ['ts-jest', { useESM: true }],
},
transformIgnorePatterns: ['node_modules/(?!(chalk)/)'],
};
10 changes: 8 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,12 @@
"format": "prettier --write .",
"lint": "eslint --ext .ts,.tsx src",
"build": "tsup src/index.ts --dts",
"release": "pnpm run build && changeset publish",
"changeset": "changeset",
"release": "pnpm build && changeset publish",
"version": "changeset version"
"version": "changeset version",
"test": "jest",
"test:watch": "jest --watch",
"test:coverage": "jest --coverage"
},
"exports": {
".": {
Expand All @@ -40,14 +43,17 @@
"type": "module",
"devDependencies": {
"@changesets/cli": "^2.27.1",
"@types/jest": "^29.5.12",
"@types/webpack": "^5.28.5",
"@typescript-eslint/eslint-plugin": "^6.18.1",
"@typescript-eslint/parser": "^6.18.1",
"eslint": "^8.56.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.1.2",
"jest": "^29.7.0",
"next": "^14.0.4",
"prettier": "^3.1.1",
"ts-jest": "^29.2.5",
"tsup": "^8.0.1",
"typescript": "^5.3.3"
},
Expand Down
Loading

0 comments on commit bd2a9e0

Please sign in to comment.