forked from tracespace/tracespace
-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
151 lines (127 loc) · 3.87 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
/* global Promise */
// pcb-stackup main
'use strict'
var extend = require('xtend')
var runParallel = require('run-parallel')
var runWaterfall = require('run-waterfall')
var gerberToSvg = require('gerber-to-svg')
var createStackup = require('pcb-stackup-core')
var wtg = require('whats-that-gerber')
module.exports = function pcbStackup(layers, options, done) {
var result
if (typeof options === 'function') {
done = options
options = null
}
validateLayersInput(layers)
// promise mode
if (done == null) {
if (typeof Promise !== 'function') {
throw new Error('No callback specified and global Promise not found')
}
result = new Promise(function(resolve, reject) {
done = function callbackToPromise(error, stackup) {
if (error) return reject(error)
resolve(stackup)
}
})
}
var layerTypes = wtg(
layers
.map(function(layer) {
return layer.filename
})
.filter(Boolean)
)
runWaterfall(
[
// render all layers with gerber-to-svg in parallel
function renderAllLayers(next) {
var layerTasks = layers.map(makeRenderLayerTask)
runParallel(layerTasks, next)
},
// using the result of renderAllLayers, build the stackup
function renderStackup(stackupLayers, next) {
var stackup = createStackup(stackupLayers, options)
stackup.layers = stackupLayers
next(null, stackup)
},
],
function finish(error, stackup) {
// ensure only error is passed if it exists
if (error) return done(error)
done(null, stackup)
}
)
// if in Promise mode, return the Promise
return result
// map an pcb-stackup input layer into a function that will call a callback
// once a pcb-stackup-core input layer is ready
function makeRenderLayerTask(layer) {
return function renderLayer(next) {
var stackupLayer = makeBaseStackupLayer(layer)
if (stackupLayer.converter) return next(null, stackupLayer)
var converter = gerberToSvg(
stackupLayer.gerber,
stackupLayer.options,
function handleLayerDone(error) {
if (error) return next(error)
stackupLayer.converter = converter
next(null, stackupLayer)
}
)
}
}
// extend pcb-stackup input layer with necessary details for pcb-stackup-core
function makeBaseStackupLayer(layer) {
var layerSide = layer.side
var layerType = layer.type
if (
layer.filename &&
typeof layerSide === 'undefined' &&
typeof layerType === 'undefined'
) {
var gerberId = layerTypes[layer.filename]
layerSide = gerberId.side
layerType = gerberId.type
}
var layerOptions = extend(layer.options)
if (layerOptions.plotAsOutline == null && layerType === wtg.TYPE_OUTLINE) {
layerOptions.plotAsOutline = true
}
if (
options &&
options.outlineGapFill != null &&
layerOptions.plotAsOutline
) {
layerOptions.plotAsOutline = options.outlineGapFill
}
return extend(layer, {
side: layerSide,
type: layerType,
options: layerOptions,
})
}
}
function validateLayersInput(layers) {
if (!Array.isArray(layers)) {
throw new Error('first argument should be an array of layers')
}
var layerErrors = layers
.map(getLayerValidationError)
.filter(Boolean)
.join(', ')
if (layerErrors) throw new Error(layerErrors)
}
function getLayerValidationError(layer, index) {
var result = wtg.validate(layer)
var error = null
if (!layer.converter && !layer.gerber) {
error = 'is missing gerber source or cached converter'
} else if (!layer.filename && !layer.type) {
error = 'is missing filename or side/type'
} else if (!layer.filename && !result.valid) {
error = 'has invalid side/type (' + layer.side + '/' + layer.type + ')'
}
return error ? 'layer ' + index + ' ' + error : null
}