Skip to content

Commit 930c7b8

Browse files
authored
Merge branch 'main' into feat/ssr-component
2 parents b1d7285 + 6c5c899 commit 930c7b8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

76 files changed

+119516
-34474
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
const Processors = require('postcss')
2+
const unitTransform = require('../index')
3+
4+
describe('wxss解析', () => {
5+
test('wxss文件样式解析', () => {
6+
const input = `
7+
.box{
8+
width: 100px;
9+
height: 200rpx;
10+
border: 0.5px solid red;
11+
margin: 0.5px 100px;
12+
transform: translate(0px, 0rpx);
13+
font-size: 0rpx;
14+
}`
15+
const result = Processors([unitTransform]).process(input)
16+
expect(result.css).toBe(`
17+
.box{
18+
width: 200px;
19+
height: 200px;
20+
border: 1px solid red;
21+
margin: 1px 200px;
22+
transform: translate(0px, 0px);
23+
font-size: 0px;
24+
}`)
25+
})
26+
})

packages/postcss-unit-transform/index.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@ function plugin (opts) {
77
root.walkDecls(function (decl) {
88
let value = decl.value
99
value = value.replace(/\b-?(\d+(\.\d+)?)px\b/ig, function (match, size) {
10-
// 绝对值<1的非0数值转十进制后会被转成0,赋值为1
11-
return Number(size) === 0 ? '0px': parseInt(size, 10) !== 0? (parseInt(size, 10) * 2) + 'px': '1px'
10+
return Number(size) === 0 ? '0px': parseFloat(size) * 2 + 'px'
1211
}).replace(/\b-?(\d+(\.\d+)?)rpx\b/ig, function (match, size) {
1312
return size + 'px'
1413
})

packages/postcss-unit-transform/package.json

+27-1
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,38 @@
44
"description": "小程序单位转换",
55
"main": "index.js",
66
"scripts": {
7-
"test": "echo \"Error: no test specified\" && exit 1"
7+
"test": "jest",
8+
"test:clear": "jest --clearCache",
9+
"test:cov": "jest --coverage",
10+
"test:updateSnapshot": "jest --updateSnapshot",
11+
"test:ci": "cross-env NODE_ENV=test jest --ci -i"
12+
},
13+
"jest": {
14+
"testEnvironment": "node",
15+
"transform": {
16+
"^.+\\.tsx?$": "ts-jest"
17+
},
18+
"testRegex": "(/postcss-unit-transform/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$",
19+
"moduleFileExtensions": [
20+
"ts",
21+
"tsx",
22+
"js",
23+
"jsx",
24+
"json",
25+
"node"
26+
],
27+
"testPathIgnorePatterns": [
28+
"/node_modules/"
29+
]
830
},
931
"author": "luckyadam",
1032
"license": "MIT",
1133
"dependencies": {
1234
"postcss": "^6.0.21",
1335
"typescript": "^4.7.4"
36+
},
37+
"devDependencies": {
38+
"jest": "^29.7.0",
39+
"ts-jest": "^29.0.5"
1440
}
1541
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"compilerOptions": {
3+
"esModuleInterop": true
4+
}
5+
}

packages/taro-cli-convertor/__tests__/__mocks__/fs-extra.js

+124-27
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,40 @@
22

33
const path = require('path')
44

5+
const fsSystem = jest.requireActual('fs-extra')
56
// 存储文件信息,包括文件路径和对应的内容
67
const oriFileMap = new Map()
78

89
// 保存转换后的文件
910
const resFileMap = new Map()
1011

12+
/**
13+
* 输出模拟文件的所有path结构
14+
*/
15+
const flatteningFile = (file,path = '',result = {}) => {
16+
for(const filePath in file){
17+
if(typeof file[filePath] === 'object' && file[filePath] !== null){
18+
result[path + filePath] = file[filePath]
19+
flatteningFile(file[filePath], path + filePath, result)
20+
} else {
21+
result[path + filePath] = file[filePath]
22+
}
23+
}
24+
}
25+
1126
/**
1227
* 保存文件信息
1328
*
1429
* @param { string } root 工程根目录
1530
* @param { map } newMockFiles
1631
*/
1732
function setMockFiles (root, newMockFiles) {
18-
for (const file in newMockFiles) {
19-
oriFileMap.set(normalizePath(path.join(root, file)), newMockFiles[file])
33+
const flatteningFileRes = {}
34+
flatteningFile(newMockFiles,'',flatteningFileRes)
35+
for (const file in flatteningFileRes) {
36+
oriFileMap.set(normalizePath(path.join(root, file)), flatteningFileRes[file])
2037
}
38+
oriFileMap.set(root,newMockFiles)
2139
}
2240

2341

@@ -36,8 +54,10 @@ function getMockFiles () {
3654
* @param { map } updateFiles
3755
*/
3856
function updateMockFiles (root, updateFiles) {
39-
for (const file in updateFiles) {
40-
oriFileMap.set(normalizePath(path.join(root, file)), updateFiles[file])
57+
const flatteningFileRes = {}
58+
flatteningFile(updateFiles,'',flatteningFileRes)
59+
for (const file in flatteningFileRes) {
60+
oriFileMap.set(normalizePath(path.join(root, file)), flatteningFileRes[file])
4161
}
4262
}
4363

@@ -70,40 +90,55 @@ function deleteMockFiles (key) {
7090
* @param { 文件路径 } path
7191
* @returns
7292
*/
73-
function readFileSyncMock (path) {
93+
function readFileSyncMock (path, type) {
7494
if (path === undefined || path === null || path === '') {
7595
throw new Error(`文件路径异常,path:${path}`)
7696
}
7797

7898
path = normalizePath(path)
79-
99+
80100
if (!existsSyncMock(path)) {
81101
throw new Error(`文件不存在,path:${path}`)
82102
}
103+
const fileMap = oriFileMap.has(path) ? oriFileMap : resFileMap
104+
const content = fileMap.get(path)
83105

84-
return oriFileMap.get(path)
106+
return content !== undefined ? content : fsSystem.readFileSync(path,type)
85107
}
86108

87109
/**
88110
* 判断文件是否存在
89111
*
90112
*/
91-
function existsSyncMock (path) {
92-
if (typeof path !== 'string' || path === '') {
113+
function existsSyncMock (pathParam) {
114+
/**
115+
* 针对于测试 generateConfigFiles 函数需要,因为 generateConfigFiles 中会查找 taro 子包中的文件
116+
* jest.requireActual('fs-extra') 操作使用的是真实fs-extra模块,非模拟,所以会查找真实路径
117+
*/
118+
if(fsSystem.existsSync(pathParam) && path.isAbsolute(pathParam)) return true
119+
120+
if (typeof pathParam !== 'string' || pathParam === '') {
93121
return false
94122
}
95123

96-
path = normalizePath(path)
124+
pathParam = normalizePath(pathParam)
97125

98-
const parts = path.split('/')
126+
const parts = pathParam.split('/')
99127
// 根据是否有后缀名判断为文件
100128
if (parts[parts.length - 1].includes('.')) {
101-
if (oriFileMap.get(path) === undefined) {
102-
return false
129+
let isFile = true
130+
if (oriFileMap.get(pathParam) === undefined) {
131+
isFile = false
132+
}
133+
if(resFileMap.get(pathParam)){
134+
isFile = true
103135
}
136+
return isFile
137+
}
138+
// 判断文件夹
139+
if(oriFileMap.get(pathParam) && !parts[parts.length - 1].includes('.')){
104140
return true
105141
}
106-
107142
// 文件夹内默认不存在
108143
return false
109144
}
@@ -122,7 +157,8 @@ function ensureDirSyncMock () {
122157
*
123158
* @returns 默认存在
124159
*/
125-
function ensureDirMock () {
160+
function ensureDirMock (path) {
161+
resFileMap.set(path,'')
126162
return true
127163
}
128164

@@ -131,7 +167,9 @@ function ensureDirMock () {
131167
*
132168
* @returns
133169
*/
134-
function mkdirSyncMock () {
170+
function mkdirSyncMock (path) {
171+
path = normalizePath(path)
172+
resFileMap.set(path,'')
135173
return true
136174
}
137175

@@ -148,11 +186,11 @@ function appendFileMock (path, appendContent) {
148186
}
149187

150188
path = normalizePath(path)
151-
if (oriFileMap.get(path)) {
152-
const newContent = oriFileMap.get(path) + appendContent
153-
oriFileMap.set(path, newContent)
189+
if (resFileMap.get(path)) {
190+
const newContent = resFileMap.get(path) + appendContent
191+
resFileMap.set(path, newContent)
154192
}
155-
oriFileMap.set(path, appendContent)
193+
resFileMap.set(path, appendContent)
156194
}
157195

158196
/**
@@ -169,6 +207,8 @@ function writeFileSyncMock (path, data) {
169207

170208
path = normalizePath(path)
171209

210+
data = Buffer.isBuffer(data) ? Buffer.from(data).toString('utf8') : data
211+
172212
resFileMap.set(path, data)
173213
}
174214

@@ -228,7 +268,7 @@ function isDir (path) {
228268
}
229269

230270
/**
231-
* 获取状态
271+
* 获取文件或目录状态,在处理路径为符号链接时返回链接指向的文件或目录的状态
232272
*/
233273
function statSyncMock (path) {
234274
if (typeof path !== 'string' || path === '') {
@@ -243,14 +283,64 @@ function statSyncMock (path) {
243283
}
244284
}
245285

286+
/**
287+
* 获取文件或目录状态,在处理路径为符号链接时返回链接自身的文件或目录的状态
288+
*/
289+
function lstatSyncMock (path) {
290+
if (typeof path !== 'string' || path === '') {
291+
return
292+
}
293+
294+
path = normalizePath(path)
295+
// 返回包含状态信息的对象
296+
return {
297+
isFile: () => customIsFile(path),
298+
isDirectory: () => customIsDirectory(path),
299+
isSymbolicLink: () => false
300+
}
301+
}
302+
303+
/**
304+
* 读取文件夹下的内容
305+
*/
306+
function readdirSyncMock (source){
307+
source = normalizePath(source)
308+
const parts = source.split('/')
309+
if(oriFileMap.get(source) && !parts[parts.length - 1].includes('.')){
310+
const fileName = []
311+
Object.keys(oriFileMap.get(source)).forEach((item) => {
312+
fileName.push(item)
313+
})
314+
return fileName
315+
} else {
316+
return fsSystem.readdirSync(source)
317+
}
318+
}
319+
320+
/**
321+
* 文件复制
322+
*/
323+
function copyFileSyncMock (sourcePath, destinationPath){
324+
resFileMap.set(destinationPath, oriFileMap.get(sourcePath))
325+
}
326+
327+
function copyFileMock (sourcePath, destinationPath){
328+
resFileMap.set(destinationPath, oriFileMap.get(sourcePath))
329+
}
330+
246331
// 自定义的 isFile 函数
247332
function customIsFile (path) {
248-
return oriFileMap.get(path)
333+
let isFileRes = false
334+
const fileMap = oriFileMap.has(path) ? oriFileMap : resFileMap
335+
if(fileMap.has(path)){
336+
isFileRes = typeof fileMap.get(path) === 'string'
337+
}
338+
return isFileRes
249339
}
250340

251341
// 自定义的 isDirectory 函数
252342
function customIsDirectory (path) {
253-
if (typeof path !== 'string' || path === '') {
343+
if (typeof path === 'string' && path.includes('.') && path.indexOf('.') !== 0) {
254344
return false
255345
}
256346
return true
@@ -267,21 +357,28 @@ function normalizePath (path) {
267357
}
268358

269359
module.exports = {
270-
...jest.requireActual('fs-extra'),
271-
readFileSync: jest.fn((content) => readFileSyncMock(content)),
360+
...fsSystem,
361+
readFileSync: jest.fn((content,type) => readFileSyncMock(content,type)),
272362
existsSync: jest.fn((path) => existsSyncMock(path)),
273363
ensureDirSync: jest.fn(() => ensureDirSyncMock()),
274364
ensureDir: jest.fn(() => ensureDirMock()),
275-
mkdirSync: jest.fn(() => mkdirSyncMock()),
365+
mkdirSync: jest.fn((path) => mkdirSyncMock(path)),
276366
appendFile: jest.fn((path, appendContent) => appendFileMock(path, appendContent)),
277367
writeFileSync: jest.fn((path, data) => writeFileSyncMock(path, data)),
278368
copySync: jest.fn((from, to) => copySyncMock(from, to)),
279369
statSync: jest.fn((path) => statSyncMock(path)),
370+
lstatSync: jest.fn((path) => lstatSyncMock(path)),
371+
readdirSync:jest.fn((source) => readdirSyncMock(source)),
372+
copyFileSync:jest.fn((sourcePath,destinationPath) => copyFileSyncMock(sourcePath,destinationPath)),
373+
copyFile:jest.fn((sourcePath,destinationPath) => copyFileMock(sourcePath,destinationPath)),
374+
writeJSONSync:jest.fn(() => true)
280375
}
281376

282377
module.exports.setMockFiles = setMockFiles
283378
module.exports.getMockFiles = getMockFiles
284379
module.exports.clearMockFiles = clearMockFiles
285380
module.exports.getResMapFile = getResMapFile
286381
module.exports.updateMockFiles = updateMockFiles
287-
module.exports.deleteMockFiles = deleteMockFiles
382+
module.exports.deleteMockFiles = deleteMockFiles
383+
module.exports.resFileMap = resFileMap
384+
module.exports.normalizePath = normalizePath

packages/taro-cli-convertor/__tests__/__mocks__/path.js

+7-2
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,16 @@ function joinMock (...pathSegments) {
1717
// 初始化一个数组用于保存最终路径的各个部分
1818
const finalPathSegments = []
1919

20-
for (const segment of pathSegments) {
20+
for (let segment of pathSegments) {
21+
// 将路劲中的 `\\` 替换为 `/` (示例:"E:\\code\\taro-16\\packages\\taro-cli")
22+
if(segment.includes(`\\`)){
23+
segment = segment.replace(/\\/g, '/')
24+
}
25+
2126
// 去掉路径段两端的斜杠并分割路径
2227
const segments = segment.split('/').filter(processPathSegment)
2328

24-
// 处理路径段中的 `..`
29+
// 处理路径段中的 `..`
2530
for (const subSegment of segments) {
2631
if (subSegment === '..') {
2732
// 如果是 `..`,则回退一层

0 commit comments

Comments
 (0)