Skip to content

Commit 0795867

Browse files
committed
initial commit
0 parents  commit 0795867

15 files changed

+472
-0
lines changed

.eslintrc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"parserOptions": {
3+
"ecmaVersion": 6,
4+
"sourceType": "script"
5+
}
6+
}

.gitignore

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Logs
2+
logs
3+
*.log
4+
npm-debug.log*
5+
6+
# Runtime data
7+
pids
8+
*.pid
9+
*.seed
10+
11+
# Directory for instrumented libs generated by jscoverage/JSCover
12+
lib-cov
13+
14+
# Coverage directory used by tools like istanbul
15+
coverage
16+
17+
# nyc test coverage
18+
.nyc_output
19+
20+
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
21+
.grunt
22+
23+
# node-waf configuration
24+
.lock-wscript
25+
26+
# Compiled binary addons (http://nodejs.org/api/addons.html)
27+
build/Release
28+
29+
# Dependency directories
30+
node_modules
31+
jspm_packages
32+
33+
# Optional npm cache directory
34+
.npm
35+
36+
# Optional REPL history
37+
.node_repl_history

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2016 Vitaly Gordon (https://github.com/xpl)
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# get-source
2+
3+
Platform-agnostic source code inspection, with sourcemaps support.
4+
5+
```bash
6+
npm install get-source
7+
```
8+
9+
## Features
10+
11+
- [x] Allows to read source code files in Node and browsers
12+
- [x] Full sourcemap support (path resolving, external/embedded linking and long chains)
13+
- [x] **Synchronous** API — which is good when you implement a debugging tool (e.g. logging)
14+
- [x] Built-in cache
15+
16+
## What for
17+
18+
- [x] Call stacks enhanced with source code information (see [StackTracey](https://github.com/xpl/stacktracey) library)
19+
- [x] Advanced logging / assertion printing
20+
21+
## Usage
22+
23+
```javascript
24+
getSource = require ('get-source')
25+
```
26+
27+
Will read `./scripts/index.min.js` synchronously (either via XHR, or by filesystem API, depending on the environment):
28+
29+
```javascript
30+
file = getSource ('./scripts/index.min.js')
31+
```
32+
33+
Result will contain following fields:
34+
35+
```javascript
36+
file.path // normalized file path
37+
file.text // text contents
38+
file.lines // array of lines
39+
```
40+
41+
And following methods:
42+
43+
```javascript
44+
file.resolve ({ line: 1, column: 8 }) // indexes here start from 1 (by widely accepted convention). Zero indexes are invalid.
45+
```
46+
47+
It will look through the sourcemap chain, returning following:
48+
49+
```
50+
{
51+
line: <original line number>,
52+
column: <original column number>,
53+
sourceFile: <original source file object>
54+
sourceLine: <original source line text, trimmed>
55+
}
56+
```
57+
58+
In that returned object, `sourceFile` is the same kind of object that `getSource` returns. So you can access its `text`, `lines` and `path` fields to obtain the full information. And the `sourceLine` is returned just for the convenience, as a shortcut.
59+
60+
## Error handling
61+
62+
In case of a nonexistent file:
63+
64+
```
65+
nonsense = getSource ('/some/nonexistent/file')
66+
67+
nonsense.text // should be '' (so it's safe to access without checking)
68+
nonsense.error // should be Error object, representing an actual error thrown during reading/parsing
69+
```
70+
71+
Calling `resolve` on an erroneous file:
72+
73+
```
74+
resolved = nonsense.resolve ({ line: 5, column: 0 })
75+
76+
resolved.error // should be Error object, representing an actual error thrown during reading/parsing
77+
resolved.sourceLine // empty string (so it's safe to access without checking)
78+
```

get-source.js

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
"use strict";
2+
3+
/* ------------------------------------------------------------------------ */
4+
5+
const O = Object,
6+
isBrowser = (typeof window !== 'undefined') && (window.window === window) && window.navigator,
7+
SourceMapConsumer = require ('source-map').SourceMapConsumer,
8+
path = require ('./impl/path'),
9+
memoize = require ('lodash.memoize'),
10+
lastOf = x => x[x.length - 1]
11+
12+
/* ------------------------------------------------------------------------ */
13+
14+
const newSourceFileMemoized = memoize (file => new SourceFile (file))
15+
16+
const getSource = module.exports = file => newSourceFileMemoized (path.normalize (file))
17+
18+
/* ------------------------------------------------------------------------ */
19+
20+
class SourceMap {
21+
22+
constructor (originalFilePath, sourceMapPath) {
23+
24+
this.file = getSource (path.relativeToFile (originalFilePath, sourceMapPath))
25+
this.parsed = (this.file.text && SourceMapConsumer (JSON.parse (this.file.text))) || null
26+
this.sourceFor = memoize (this.sourceFor.bind (this))
27+
}
28+
29+
sourceFor (file) {
30+
const content = this.parsed.sourceContentFor (file, true /* return null on missing */)
31+
const fullPath = path.relativeToFile (this.file.path, file)
32+
return content ? new SourceFile (fullPath, content) : getSource (fullPath)
33+
}
34+
35+
resolve (loc) {
36+
37+
const originalLoc = this.parsed.originalPositionFor (loc)
38+
39+
return this.sourceFor (originalLoc.source)
40+
.resolve (O.assign ({}, loc, {
41+
line: originalLoc.line,
42+
column: originalLoc.column,
43+
name: originalLoc.name }))
44+
}
45+
}
46+
47+
/* ------------------------------------------------------------------------ */
48+
49+
class SourceFile {
50+
51+
constructor (path, text /* optional */) {
52+
53+
this.path = path
54+
55+
if (text) {
56+
this.text = text }
57+
58+
else {
59+
try {
60+
if (isBrowser) {
61+
62+
let xhr = new XMLHttpRequest ()
63+
64+
xhr.open ('GET', path, false /* SYNCHRONOUS XHR FTW :) */)
65+
xhr.send (null)
66+
67+
this.text = xhr.responseText }
68+
69+
else {
70+
this.text = require ('fs').readFileSync (path, { encoding: 'utf8' }) } }
71+
72+
catch (e) {
73+
this.error = e
74+
this.text = '' } }
75+
}
76+
77+
get lines () {
78+
return (this.lines_ = this.lines_ || this.text.split ('\n'))
79+
}
80+
81+
get sourceMap () {
82+
83+
try {
84+
if (this.sourceMap_ === undefined) {
85+
let url = this.text.match (/\# sourceMappingURL=(.+\.map)/)
86+
if (url = (url && url[1])) {
87+
this.sourceMap_ = new SourceMap (this.path, url) } } }
88+
89+
catch (e) {
90+
this.sourceMapError = e
91+
this.sourceMap_ = null }
92+
93+
return this.sourceMap_
94+
}
95+
96+
resolve (loc /* { line, column } */) /* → { line, column, sourceFile, sourceLine } */ {
97+
98+
return this.sourceMap ? this.sourceMap.resolve (loc) : O.assign ({}, loc, {
99+
100+
sourceFile: this,
101+
sourceLine: (this.lines[loc.line - 1] || ''),
102+
error: this.error
103+
})
104+
}
105+
}
106+
107+
/* ------------------------------------------------------------------------ */

impl/path.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
"use strict";
2+
3+
/* ------------------------------------------------------------------------ */
4+
5+
const path = module.exports = {
6+
7+
concat: (a, b) => {
8+
9+
const a_endsWithSlash = (a[a.length - 1] === '/'),
10+
b_startsWithSlash = (b[0] === '/')
11+
12+
return a + ((a_endsWithSlash || b_startsWithSlash) ? '' : '/') +
13+
((a_endsWithSlash && b_startsWithSlash) ? b.substring (1) : b) },
14+
15+
normalize: path => {
16+
17+
let output = [],
18+
skip = 0
19+
20+
path.split ('/').reverse ().filter (x => x !== '.').forEach (x => {
21+
22+
if (x === '..') { skip++ }
23+
else if (skip === 0) { output.push (x) }
24+
else { skip-- }
25+
})
26+
27+
return output.reverse ().join ('/')
28+
},
29+
30+
relativeToFile: (a, b) => {
31+
return path.normalize (path.concat (a.split ('/').slice (0, -1).join ('/'), b))
32+
}
33+
}
34+
35+
/* ------------------------------------------------------------------------ */

package.json

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{
2+
"name": "get-source",
3+
"version": "1.0.0",
4+
"description": "Platform-agnostic source code inspection, with sourcemaps support",
5+
"main": "get-source",
6+
"scripts": {
7+
"test": "./node_modules/.bin/mocha --reporter spec --watch"
8+
},
9+
"repository": {
10+
"type": "git",
11+
"url": "https://github.com/xpl/get-source.git"
12+
},
13+
"keywords": [
14+
"sources",
15+
"sourcemap",
16+
"read source",
17+
"cached sources"
18+
],
19+
"author": "Vitaly Gordon <rocket.mind@gmail.com>",
20+
"license": "MIT",
21+
"bugs": {
22+
"url": "https://github.com/xpl/get-source/issues"
23+
},
24+
"homepage": "https://github.com/xpl/get-source",
25+
"devDependencies": {
26+
"chai": "^3.5.0",
27+
"mocha": "^2.4.5"
28+
},
29+
"dependencies": {
30+
"lodash.memoize": "^4.1.2",
31+
"source-map": "^0.5.6"
32+
}
33+
}

0 commit comments

Comments
 (0)