Skip to content

Commit 381e680

Browse files
petebacondarwinIgorMinar
authored andcommitted
build(aio): improve error message for ignored example files (#19265)
Addresses #18707 (comment) PR Close #19265
1 parent 988b9f8 commit 381e680

5 files changed

Lines changed: 207 additions & 147 deletions

File tree

aio/tools/transforms/angular-content-package/index.js

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,25 @@ module.exports = new Package('angular-content', [basePackage, contentPackage])
2020
// Where do we get the source files?
2121
.config(function(readFilesProcessor, collectExamples) {
2222

23-
const gitignoreFile = fs.readFileSync(path.resolve(GUIDE_EXAMPLES_PATH, '.gitignore'), 'utf8');
23+
const gitignoreFilePath = path.resolve(GUIDE_EXAMPLES_PATH, '.gitignore');
24+
const gitignoreFile = fs.readFileSync(gitignoreFilePath, 'utf8');
2425
const gitignore = ignore().add(gitignoreFile);
2526

2627
const examplePaths = glob.sync('**/*', { cwd: GUIDE_EXAMPLES_PATH, dot: true, ignore: '**/node_modules/**', mark: true })
2728
.filter(filePath => filePath !== '.gitignore') // we are not interested in the .gitignore file itself
2829
.filter(filePath => !/\/$/.test(filePath)); // this filter removes the folders, leaving only files
29-
const filteredExamplePaths = gitignore.filter(examplePaths) // filter out files that match the .gitignore rules
30-
.map(filePath => path.resolve(GUIDE_EXAMPLES_PATH, filePath)); // we need the full paths for the filereader
30+
const ignoredExamplePaths = [];
31+
const resolvedExamplePaths = [];
32+
33+
examplePaths.forEach(filePath => {
34+
// filter out files that match the .gitignore rules
35+
if (gitignore.ignores(filePath)) {
36+
ignoredExamplePaths.push(filePath);
37+
} else {
38+
// we need the full paths for the filereader
39+
resolvedExamplePaths.push(path.resolve(GUIDE_EXAMPLES_PATH, filePath));
40+
}
41+
});
3142

3243
readFilesProcessor.sourceFiles = readFilesProcessor.sourceFiles.concat([
3344
{
@@ -48,7 +59,7 @@ module.exports = new Package('angular-content', [basePackage, contentPackage])
4859
},
4960
{
5061
basePath: CONTENTS_PATH,
51-
include: filteredExamplePaths,
62+
include: resolvedExamplePaths,
5263
fileReader: 'exampleFileReader'
5364
},
5465
{
@@ -69,6 +80,7 @@ module.exports = new Package('angular-content', [basePackage, contentPackage])
6980
]);
7081

7182
collectExamples.exampleFolders.push('examples');
83+
collectExamples.registerIgnoredExamples(ignoredExamplePaths, gitignoreFilePath);
7284
})
7385

7486

aio/tools/transforms/examples-package/processors/collect-examples.js

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,26 @@ module.exports = function collectExamples(exampleMap, regionParser, log, createD
66
$runAfter: ['files-read'],
77
$runBefore: ['parsing-tags'],
88
$validate: {exampleFolders: {presence: true}},
9-
$process: function(docs) {
9+
exampleFolders: [],
10+
ignoredExamples: {},
11+
/**
12+
* Call this method to indicate to the processor that some files, that actually exist,
13+
* have been filtered out from being processed.
14+
* @param paths an array of relative paths to the examples that have been ignored.
15+
* @param gitIgnorePath the path to the gitignore file that caused this example to be ignored.
16+
*/
17+
registerIgnoredExamples(paths, gitIgnorePath) {
18+
paths.forEach(path => { this.ignoredExamples[path] = gitIgnorePath; });
19+
},
20+
/**
21+
* Call this method to find out if an example was ignored.
22+
* @param path a relative path to the example file to test for being ignored.
23+
* @returns the path to the .gitignore file.
24+
*/
25+
isExampleIgnored(path) {
26+
return this.ignoredExamples[path];
27+
},
28+
$process(docs) {
1029
const exampleFolders = this.exampleFolders;
1130
const regionDocs = [];
1231
docs = docs.filter((doc) => {

aio/tools/transforms/examples-package/processors/collect-examples.spec.js

Lines changed: 147 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -23,161 +23,175 @@ describe('collectExampleRegions processor', () => {
2323
processor.exampleFolders = ['examples-1', 'examples-2'];
2424
});
2525

26-
it('should identify example files that are in the exampleFolders', () => {
27-
const docs = [
28-
createDoc('A', 'examples-1/x/app.js'), createDoc('B', 'examples-1/y/index.html'),
29-
createDoc('C', 'examples-2/s/app.js'), createDoc('D', 'examples-2/t/style.css'),
30-
createDoc('E', 'other/b/c.js')
31-
];
26+
describe('$process', () => {
3227

33-
processor.$process(docs);
28+
it('should identify example files that are in the exampleFolders', () => {
29+
const docs = [
30+
createDoc('A', 'examples-1/x/app.js'), createDoc('B', 'examples-1/y/index.html'),
31+
createDoc('C', 'examples-2/s/app.js'), createDoc('D', 'examples-2/t/style.css'),
32+
createDoc('E', 'other/b/c.js')
33+
];
3434

35-
expect(exampleMap['examples-1']['x/app.js']).toBeDefined();
36-
expect(exampleMap['examples-1']['y/index.html']).toBeDefined();
37-
expect(exampleMap['examples-2']['s/app.js']).toBeDefined();
38-
expect(exampleMap['examples-2']['t/style.css']).toBeDefined();
35+
processor.$process(docs);
3936

40-
expect(exampleMap['other']).toBeUndefined();
41-
});
37+
expect(exampleMap['examples-1']['x/app.js']).toBeDefined();
38+
expect(exampleMap['examples-1']['y/index.html']).toBeDefined();
39+
expect(exampleMap['examples-2']['s/app.js']).toBeDefined();
40+
expect(exampleMap['examples-2']['t/style.css']).toBeDefined();
4241

43-
it('should remove example files from the docs collection', () => {
44-
const docs = [
45-
createDoc('Example A', 'examples-1/x/app.js'),
46-
createDoc('Example B', 'examples-1/y/index.html'),
47-
createDoc('Other doc 1', 'examples-2/t/style.css', 'content'),
48-
createDoc('Example C', 'examples-2/s/app.js'),
49-
createDoc('Other doc 2', 'other/b/c.js', 'content')
50-
];
42+
expect(exampleMap['other']).toBeUndefined();
43+
});
5144

52-
const processedDocs = processor.$process(docs);
45+
it('should remove example files from the docs collection', () => {
46+
const docs = [
47+
createDoc('Example A', 'examples-1/x/app.js'),
48+
createDoc('Example B', 'examples-1/y/index.html'),
49+
createDoc('Other doc 1', 'examples-2/t/style.css', 'content'),
50+
createDoc('Example C', 'examples-2/s/app.js'),
51+
createDoc('Other doc 2', 'other/b/c.js', 'content')
52+
];
5353

54-
expect(processedDocs.filter(doc => doc.docType === 'example-file')).toEqual([]);
55-
});
54+
const processedDocs = processor.$process(docs);
5655

57-
it('should not remove docs from the docs collection that are not example files', () => {
58-
const docs = [
59-
createDoc('Example A', 'examples-1/x/app.js'),
60-
createDoc('Example B', 'examples-1/y/index.html'),
61-
createDoc('Other doc 1', 'examples-2/t/style.css', 'content'),
62-
createDoc('Example C', 'examples-2/s/app.js'),
63-
createDoc('Other doc 2', 'other/b/c.js', 'content')
64-
];
56+
expect(processedDocs.filter(doc => doc.docType === 'example-file')).toEqual([]);
57+
});
6558

66-
const processedDocs = processor.$process(docs);
59+
it('should not remove docs from the docs collection that are not example files', () => {
60+
const docs = [
61+
createDoc('Example A', 'examples-1/x/app.js'),
62+
createDoc('Example B', 'examples-1/y/index.html'),
63+
createDoc('Other doc 1', 'examples-2/t/style.css', 'content'),
64+
createDoc('Example C', 'examples-2/s/app.js'),
65+
createDoc('Other doc 2', 'other/b/c.js', 'content')
66+
];
67+
68+
const processedDocs = processor.$process(docs);
69+
70+
expect(processedDocs.filter(doc => doc.docType !== 'example-file'))
71+
.toEqual(jasmine.objectContaining([
72+
createDoc('Other doc 1', 'examples-2/t/style.css', 'content'),
73+
createDoc('Other doc 2', 'other/b/c.js', 'content')
74+
]));
75+
});
6776

68-
expect(processedDocs.filter(doc => doc.docType !== 'example-file'))
69-
.toEqual(jasmine.objectContaining([
77+
it('should call `regionParser` from with the content and file extension of each example doc',
78+
() => {
79+
const docs = [
80+
createDoc('Example A', 'examples-1/x/app.js'),
81+
createDoc('Example B', 'examples-1/y/index.html'),
7082
createDoc('Other doc 1', 'examples-2/t/style.css', 'content'),
83+
createDoc('Example C', 'examples-2/s/app.js'),
7184
createDoc('Other doc 2', 'other/b/c.js', 'content')
72-
]));
73-
});
85+
];
7486

75-
it('should call `regionParser` from with the content and file extension of each example doc',
76-
() => {
77-
const docs = [
78-
createDoc('Example A', 'examples-1/x/app.js'),
79-
createDoc('Example B', 'examples-1/y/index.html'),
80-
createDoc('Other doc 1', 'examples-2/t/style.css', 'content'),
81-
createDoc('Example C', 'examples-2/s/app.js'),
82-
createDoc('Other doc 2', 'other/b/c.js', 'content')
83-
];
87+
processor.$process(docs);
8488

85-
processor.$process(docs);
89+
expect(regionParser).toHaveBeenCalledTimes(3);
90+
expect(regionParser).toHaveBeenCalledWith('Example A', 'js');
91+
expect(regionParser).toHaveBeenCalledWith('Example B', 'html');
92+
expect(regionParser).toHaveBeenCalledWith('Example C', 'js');
93+
});
8694

87-
expect(regionParser).toHaveBeenCalledTimes(3);
88-
expect(regionParser).toHaveBeenCalledWith('Example A', 'js');
89-
expect(regionParser).toHaveBeenCalledWith('Example B', 'html');
90-
expect(regionParser).toHaveBeenCalledWith('Example C', 'js');
91-
});
9295

96+
it('should attach parsed content as renderedContent to the example file docs', () => {
97+
const docs = [
98+
createDoc('A', 'examples-1/x/app.js'),
99+
createDoc('B', 'examples-1/y/index.html'),
100+
createDoc('C', 'examples-2/s/app.js'),
101+
createDoc('D', 'examples-2/t/style.css'),
102+
];
93103

94-
it('should attach parsed content as renderedContent to the example file docs', () => {
95-
const docs = [
96-
createDoc('A', 'examples-1/x/app.js'),
97-
createDoc('B', 'examples-1/y/index.html'),
98-
createDoc('C', 'examples-2/s/app.js'),
99-
createDoc('D', 'examples-2/t/style.css'),
100-
];
104+
processor.$process(docs);
101105

102-
processor.$process(docs);
106+
expect(exampleMap['examples-1']['x/app.js'].renderedContent).toEqual('PARSED:A');
107+
expect(exampleMap['examples-1']['y/index.html'].renderedContent).toEqual('PARSED:B');
108+
expect(exampleMap['examples-2']['s/app.js'].renderedContent).toEqual('PARSED:C');
109+
expect(exampleMap['examples-2']['t/style.css'].renderedContent).toEqual('PARSED:D');
103110

104-
expect(exampleMap['examples-1']['x/app.js'].renderedContent).toEqual('PARSED:A');
105-
expect(exampleMap['examples-1']['y/index.html'].renderedContent).toEqual('PARSED:B');
106-
expect(exampleMap['examples-2']['s/app.js'].renderedContent).toEqual('PARSED:C');
107-
expect(exampleMap['examples-2']['t/style.css'].renderedContent).toEqual('PARSED:D');
111+
});
108112

109-
});
113+
it('should create region docs for each region in the example file docs', () => {
114+
const docs = [
115+
createDoc('/* #docregion X */\nA', 'examples-1/x/app.js'),
116+
createDoc('<!-- #docregion Y -->\nB', 'examples-1/y/index.html'),
117+
createDoc('/* #docregion Z */\nC', 'examples-2/t/style.css'),
118+
];
119+
120+
const newDocs = processor.$process(docs);
121+
122+
expect(newDocs.length).toEqual(3);
123+
expect(newDocs).toEqual([
124+
jasmine.objectContaining({
125+
docType: 'example-region',
126+
name: 'dummy',
127+
id: 'examples-1/x/app.js#dummy',
128+
contents: 'js'
129+
}),
130+
jasmine.objectContaining({
131+
docType: 'example-region',
132+
name: 'dummy',
133+
id: 'examples-1/y/index.html#dummy',
134+
contents: 'html'
135+
}),
136+
jasmine.objectContaining({
137+
docType: 'example-region',
138+
name: 'dummy',
139+
id: 'examples-2/t/style.css#dummy',
140+
contents: 'css'
141+
})
142+
]);
143+
});
110144

111-
it('should create region docs for each region in the example file docs', () => {
112-
const docs = [
113-
createDoc('/* #docregion X */\nA', 'examples-1/x/app.js'),
114-
createDoc('<!-- #docregion Y -->\nB', 'examples-1/y/index.html'),
115-
createDoc('/* #docregion Z */\nC', 'examples-2/t/style.css'),
116-
];
117-
118-
const newDocs = processor.$process(docs);
119-
120-
expect(newDocs.length).toEqual(3);
121-
expect(newDocs).toEqual([
122-
jasmine.objectContaining({
123-
docType: 'example-region',
124-
name: 'dummy',
125-
id: 'examples-1/x/app.js#dummy',
126-
contents: 'js'
127-
}),
128-
jasmine.objectContaining({
129-
docType: 'example-region',
130-
name: 'dummy',
131-
id: 'examples-1/y/index.html#dummy',
132-
contents: 'html'
133-
}),
134-
jasmine.objectContaining({
135-
docType: 'example-region',
136-
name: 'dummy',
137-
id: 'examples-2/t/style.css#dummy',
138-
contents: 'css'
139-
})
140-
]);
145+
it('should attach region docs to the example file docs', () => {
146+
const docs = [
147+
createDoc('/* #docregion X */\nA', 'examples-1/x/app.js'),
148+
createDoc('<!-- #docregion Y -->\nB', 'examples-1/y/index.html'),
149+
createDoc('/* #docregion Z */\nC', 'examples-2/t/style.css'),
150+
];
151+
152+
processor.$process(docs);
153+
154+
expect(exampleMap['examples-1']['x/app.js'].regions).toEqual({
155+
dummy: {
156+
docType: 'example-region',
157+
path: 'examples-1/x/app.js',
158+
name: 'dummy',
159+
id: 'examples-1/x/app.js#dummy',
160+
aliases: ['examples-1/x/app.js#dummy'],
161+
contents: 'js'
162+
}
163+
});
164+
expect(exampleMap['examples-1']['y/index.html'].regions).toEqual({
165+
dummy: {
166+
docType: 'example-region',
167+
path: 'examples-1/y/index.html',
168+
name: 'dummy',
169+
id: 'examples-1/y/index.html#dummy',
170+
aliases: ['examples-1/y/index.html#dummy'],
171+
contents: 'html'
172+
}
173+
});
174+
expect(exampleMap['examples-2']['t/style.css'].regions).toEqual({
175+
dummy: {
176+
docType: 'example-region',
177+
path: 'examples-2/t/style.css',
178+
name: 'dummy',
179+
id: 'examples-2/t/style.css#dummy',
180+
aliases: ['examples-2/t/style.css#dummy'],
181+
contents: 'css'
182+
}
183+
});
184+
});
141185
});
142186

143-
it('should attach region docs to the example file docs', () => {
144-
const docs = [
145-
createDoc('/* #docregion X */\nA', 'examples-1/x/app.js'),
146-
createDoc('<!-- #docregion Y -->\nB', 'examples-1/y/index.html'),
147-
createDoc('/* #docregion Z */\nC', 'examples-2/t/style.css'),
148-
];
149-
150-
processor.$process(docs);
151-
152-
expect(exampleMap['examples-1']['x/app.js'].regions).toEqual({
153-
dummy: {
154-
docType: 'example-region',
155-
path: 'examples-1/x/app.js',
156-
name: 'dummy',
157-
id: 'examples-1/x/app.js#dummy',
158-
aliases: ['examples-1/x/app.js#dummy'],
159-
contents: 'js'
160-
}
161-
});
162-
expect(exampleMap['examples-1']['y/index.html'].regions).toEqual({
163-
dummy: {
164-
docType: 'example-region',
165-
path: 'examples-1/y/index.html',
166-
name: 'dummy',
167-
id: 'examples-1/y/index.html#dummy',
168-
aliases: ['examples-1/y/index.html#dummy'],
169-
contents: 'html'
170-
}
171-
});
172-
expect(exampleMap['examples-2']['t/style.css'].regions).toEqual({
173-
dummy: {
174-
docType: 'example-region',
175-
path: 'examples-2/t/style.css',
176-
name: 'dummy',
177-
id: 'examples-2/t/style.css#dummy',
178-
aliases: ['examples-2/t/style.css#dummy'],
179-
contents: 'css'
180-
}
187+
describe('filtered examples', () => {
188+
it('should indicate if an example was filtered', () => {
189+
processor.registerIgnoredExamples(['c/d/e', 'e/f/g'], 'path/to/gitignore');
190+
processor.registerIgnoredExamples(['x/y/z'], 'path/to/other/gitignore');
191+
expect(processor.isExampleIgnored('a/b/c')).toBeFalsy();
192+
expect(processor.isExampleIgnored('c/d/e')).toEqual('path/to/gitignore');
193+
expect(processor.isExampleIgnored('e/f/g')).toEqual('path/to/gitignore');
194+
expect(processor.isExampleIgnored('x/y/z')).toEqual('path/to/other/gitignore');
181195
});
182196
});
183197
});

0 commit comments

Comments
 (0)