Skip to content
This repository was archived by the owner on Aug 7, 2021. It is now read-only.

Commit ed392e5

Browse files
committed
Implement filesystem that can be used to map platform specific files
1 parent f1ba503 commit ed392e5

File tree

3 files changed

+128
-1
lines changed

3 files changed

+128
-1
lines changed

Diff for: package.json

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
"generate-android-snapshot": "./bin/generate-android-snapshot"
2727
},
2828
"dependencies": {
29+
"minimatch": "^3.0.4",
2930
"semver": "^5.4.1",
3031
"shelljs": "^0.6.0"
3132
},

Diff for: plugins/PlatformFSPlugin.js

+125
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
const { parse: parseFile, join, basename, relative } = require("path");
2+
const minimatch = require("minimatch");
3+
4+
function PlatformFSPlugin({platform, platforms, ignore}) {
5+
this.platform = platform;
6+
this.platforms = platforms;
7+
this.ignore = ignore || [];
8+
9+
const alienPlatforms = this.platforms.filter(p => p !== platform);
10+
const alienPlatformFilters = alienPlatforms.map(platform => ({
11+
endsWithSuffix: `.${platform}`,
12+
contains: `.${platform}.`
13+
})).map(({endsWithSuffix, contains}) => baseFileName =>
14+
baseFileName.endsWith(endsWithSuffix) ||
15+
baseFileName.indexOf(contains) != -1);
16+
this.isNotAlienPlatformFile = file => !alienPlatformFilters.some(basename(file));
17+
18+
const currentPlatformExt = `.${platform}`;
19+
this.trimPlatformSuffix = file => {
20+
const {dir, name, ext} = parseFile(file);
21+
if (ext === currentPlatformExt) {
22+
return join(dir, name);
23+
} else if (name.endsWith(currentPlatformExt)) {
24+
return join(dir, name.substr(0, name.length - currentPlatformExt.length) + ext);
25+
}
26+
return file;
27+
}
28+
}
29+
30+
PlatformFSPlugin.prototype.apply = function(compiler) {
31+
const context = this.context = compiler.context;
32+
const minimatchFileFilters = this.ignore.map(pattern => {
33+
const minimatchFilter = minimatch.filter(pattern);
34+
return file => minimatchFilter(relative(context, file));
35+
});
36+
37+
this.isIgnored = file => minimatchFileFilters.some(filter => filter(file));
38+
39+
compiler.inputFileSystem = this.mapFileSystem(compiler.inputFileSystem);
40+
}
41+
42+
PlatformFSPlugin.prototype.mapFileSystem = function(fs) {
43+
const platform = this.platform;
44+
const platforms = this.platforms;
45+
const alienPlatforms = this.alienPlatforms;
46+
const isNotAlienPlatformFile = this.isNotAlienPlatformFile;
47+
const trimPlatformSuffix = this.trimPlatformSuffix;
48+
const isIgnored = this.isIgnored;
49+
const isNotIgnored = file => !isIgnored(file);
50+
51+
const mappedFS = {
52+
get _statStorage() { return fs._statStorage; },
53+
get _readFileStorage() { return fs._readFileStorage; },
54+
get _readdirStorage() { return fs._readdirStorage; }
55+
};
56+
57+
["readFile", "provide", "stat", "readJson"].forEach(mapPath);
58+
["readdir"].forEach(filterResultingFiles);
59+
60+
return mappedFS;
61+
62+
/**
63+
* For FS functions that get as first argument a file path,
64+
* this will map it to a platform specific file if such file exists or fallback to the default.
65+
* Also the last argument must be a function that handles results such as (err, files[]),
66+
* it will invoke err for files that are ignored.
67+
*/
68+
function mapPath(name) {
69+
const base = fs[name];
70+
mappedFS[name] = function() {
71+
const originalFilePath = arguments[0];
72+
const callback = arguments[arguments.length - 1];
73+
if (isIgnored(originalFilePath)) {
74+
callback(new Error("File " + originalFilePath + " is ignored!"));
75+
return;
76+
}
77+
const {dir, name, ext} = parseFile(originalFilePath);
78+
const platformFilePath = join(dir, name + ("." + platform) + ext);
79+
fs.stat(platformFilePath, (err, stat) => {
80+
if (!err && stat && stat.isFile()) {
81+
arguments[0] = platformFilePath;
82+
}
83+
base.apply(fs, arguments);
84+
});
85+
}
86+
}
87+
88+
/**
89+
* For FS functions that get as a last argument a function,
90+
* that handles results such as (err, files[]),
91+
* will filter and map the returned files[].
92+
*/
93+
function filterResultingFiles(name) {
94+
const base = fs[name];
95+
mappedFS[name] = function() {
96+
const callback = arguments[arguments.length - 1];
97+
const dir = arguments[0];
98+
if (isIgnored(dir)) {
99+
// Return empty file list for filtered directories.
100+
callback(null, []);
101+
return;
102+
}
103+
arguments[arguments.length - 1] = function(err, files) {
104+
if (err) {
105+
callback(err);
106+
} else {
107+
// Create absolute paths for "ignored" testing, map platforms, and return back the base name.
108+
const result = files
109+
.map(file => join(dir, file))
110+
.filter(isNotIgnored)
111+
.filter(isNotAlienPlatformFile)
112+
.map(trimPlatformSuffix)
113+
.map(file => basename(file));
114+
115+
// app.css and app.android.css will both map into app.css and we remove duplicates:
116+
const uniqueResults = [...new Set(result)];
117+
callback(null, uniqueResults);
118+
}
119+
}
120+
base.apply(fs, arguments);
121+
}
122+
}
123+
}
124+
125+
exports.PlatformFSPlugin = PlatformFSPlugin;

Diff for: plugins/index.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@ module.exports = Object.assign({},
22
require("./GenerateBundleStarterPlugin"),
33
require("./NativeScriptJsonpPlugin"),
44
require("./NativeScriptSnapshotPlugin"),
5-
require("./PlatformSuffixPlugin")
5+
require("./PlatformSuffixPlugin"),
6+
require("./PlatformFSPlugin")
67
);

0 commit comments

Comments
 (0)