@stackline/redeyed 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json ADDED
@@ -0,0 +1,123 @@
1
+ {
2
+ "name": "@stackline/redeyed",
3
+ "version": "1.0.1",
4
+ "description": "Source-preserving JavaScript token transforms with immutable configs and parser adapters",
5
+ "type": "commonjs",
6
+ "main": "./redeyed.js",
7
+ "module": "./index.mjs",
8
+ "types": "./index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": {
12
+ "import": "./index.d.mts",
13
+ "require": "./index.d.cts",
14
+ "default": "./index.d.ts"
15
+ },
16
+ "browser": {
17
+ "import": "./dist/redeyed.browser.mjs",
18
+ "require": "./dist/redeyed.browser.cjs"
19
+ },
20
+ "import": "./index.mjs",
21
+ "require": "./redeyed.js",
22
+ "default": "./redeyed.js"
23
+ },
24
+ "./config": {
25
+ "types": "./config.d.ts",
26
+ "default": "./config.js"
27
+ },
28
+ "./config-es5": {
29
+ "types": "./config-es5.d.ts",
30
+ "default": "./config-es5.js"
31
+ },
32
+ "./package.json": "./package.json"
33
+ },
34
+ "unpkg": "./dist/redeyed.global.js",
35
+ "jsdelivr": "./dist/redeyed.global.js",
36
+ "sideEffects": false,
37
+ "files": [
38
+ "dist",
39
+ "redeyed.js",
40
+ "index.mjs",
41
+ "index.d.ts",
42
+ "index.d.cts",
43
+ "index.d.mts",
44
+ "config.js",
45
+ "config.d.ts",
46
+ "config-es5.js",
47
+ "config-es5.d.ts",
48
+ "CHANGELOG.md",
49
+ "LICENSE",
50
+ "NOTICE",
51
+ "README.md",
52
+ "SECURITY.md",
53
+ "THIRD_PARTY_LICENSES.md"
54
+ ],
55
+ "scripts": {
56
+ "clean": "node scripts/clean.mjs",
57
+ "build": "node scripts/build.mjs",
58
+ "lint": "eslint redeyed.js index.mjs scripts test docs-site",
59
+ "test:upstream": "tape test/*.js",
60
+ "test:compatibility": "node test/compatibility.js",
61
+ "test:esm": "node test/esm.mjs",
62
+ "test:types": "node node_modules/typescript-3-9/bin/tsc -p test/types/tsconfig.legacy.json && node node_modules/typescript/bin/tsc -p test/types/tsconfig.commonjs.json && node node_modules/typescript/bin/tsc -p test/types/tsconfig.modern.json",
63
+ "test:browser": "node scripts/check-browser.mjs",
64
+ "test": "npm run test:upstream && npm run test:compatibility && npm run test:esm && npm run test:types && npm run test:browser",
65
+ "test:coverage": "c8 --all --include=redeyed.js --check-coverage --lines 95 --functions 95 --branches 90 tape test/*.js",
66
+ "test:smoke": "node scripts/smoke-install.mjs && node scripts/smoke-cardinal.mjs",
67
+ "test:docs": "npm run docs:build && node scripts/check-docs.mjs",
68
+ "check:package": "publint && attw --pack .",
69
+ "pack:check": "npm pack --dry-run",
70
+ "audit:dependencies": "npm audit --omit=dev --audit-level=low",
71
+ "audit:signatures": "npm audit signatures",
72
+ "docs:build": "npm run build && node scripts/build-docs.mjs",
73
+ "docs:serve": "node scripts/serve-docs.mjs",
74
+ "verify": "npm run clean && npm run lint && npm run build && npm test && npm run test:coverage && npm run test:smoke && npm run check:package && npm run pack:check && npm run test:docs && npm run audit:dependencies",
75
+ "prepack": "npm run build"
76
+ },
77
+ "repository": {
78
+ "type": "git",
79
+ "url": "git+https://github.com/alexandroit/stackline-redeyed.git"
80
+ },
81
+ "homepage": "https://alexandro.net/docs/vanilla/redeyed/",
82
+ "bugs": {
83
+ "url": "https://github.com/alexandroit/stackline-redeyed/issues"
84
+ },
85
+ "keywords": [
86
+ "javascript",
87
+ "tokens",
88
+ "syntax",
89
+ "transform",
90
+ "source",
91
+ "parser",
92
+ "highlight",
93
+ "immutable",
94
+ "stackline"
95
+ ],
96
+ "author": "Stackline Maintainers",
97
+ "contributors": [
98
+ "Thorsten Lorenz",
99
+ "Ariya Hidayat"
100
+ ],
101
+ "license": "MIT",
102
+ "engines": {
103
+ "node": ">=12"
104
+ },
105
+ "publishConfig": {
106
+ "access": "public"
107
+ },
108
+ "dependencies": {
109
+ "esprima": "4.0.1"
110
+ },
111
+ "devDependencies": {
112
+ "@arethetypeswrong/cli": "0.18.5",
113
+ "c8": "12.0.0",
114
+ "esbuild": "0.28.2",
115
+ "eslint": "10.9.1",
116
+ "espree": "11.2.0",
117
+ "publint": "0.3.24",
118
+ "redeyed-baseline": "npm:redeyed@2.1.1",
119
+ "tape": "5.10.2",
120
+ "typescript": "7.0.2",
121
+ "typescript-3-9": "npm:typescript@3.9.10"
122
+ }
123
+ }
package/redeyed.js ADDED
@@ -0,0 +1,386 @@
1
+ ;(function () {
2
+ 'use strict'
3
+ /* global define */
4
+
5
+ var esprima
6
+ var exportFn
7
+ var toString = Object.prototype.toString
8
+ var hasOwn = Object.prototype.hasOwnProperty
9
+
10
+ if (typeof module === 'object' && typeof module.exports === 'object' && typeof require === 'function') {
11
+ esprima = require('esprima')
12
+ exportFn = function (redeyed) { module.exports = redeyed }
13
+ bootstrap(esprima, exportFn)
14
+ } else if (typeof define === 'function' && define.amd) {
15
+ define(['esprima'], function (esprima) {
16
+ return bootstrap(esprima)
17
+ })
18
+ } else if (typeof window === 'object') {
19
+ window.redeyed = bootstrap(window.esprima)
20
+ }
21
+
22
+ function bootstrap (esprima, exportFn) {
23
+ function isFunction (obj) {
24
+ return toString.call(obj) === '[object Function]'
25
+ }
26
+
27
+ function isString (obj) {
28
+ return toString.call(obj) === '[object String]'
29
+ }
30
+
31
+ function isObject (obj) {
32
+ return toString.call(obj) === '[object Object]'
33
+ }
34
+
35
+ function owns (obj, key) {
36
+ return hasOwn.call(obj, key)
37
+ }
38
+
39
+ function surroundWith (before, after) {
40
+ return function (s) { return before + s + after }
41
+ }
42
+
43
+ function isNonCircular (key) {
44
+ return key !== '_parent'
45
+ }
46
+
47
+ function objectizeString (value) {
48
+ var vals = value.split(':')
49
+
50
+ if (vals.length === 0 || vals.length > 2) {
51
+ throw new Error(
52
+ 'illegal string config: ' + value +
53
+ '\nShould be of format "before:after"'
54
+ )
55
+ }
56
+
57
+ if (vals.length === 1 || vals[1].length === 0) {
58
+ return vals.indexOf(':') < 0 ? { _before: vals[0] } : { _after: vals[0] }
59
+ }
60
+ return { _before: vals[0], _after: vals[1] }
61
+ }
62
+
63
+ function cloneConfig (value, ancestors) {
64
+ if (!isObject(value)) return value
65
+ if (ancestors.indexOf(value) !== -1) {
66
+ throw new TypeError('redeyed config must not contain circular references')
67
+ }
68
+
69
+ var clone = Object.create(null)
70
+ var nextAncestors = ancestors.concat([value])
71
+ Object.keys(value).forEach(function (key) {
72
+ clone[key] = cloneConfig(value[key], nextAncestors)
73
+ })
74
+ return clone
75
+ }
76
+
77
+ function objectize (node, parent) {
78
+ function resolve (key) {
79
+ if (node._default && node._default[key]) return node._default[key]
80
+ if (!parent) return undefined
81
+ return parent._default ? parent._default[key] : undefined
82
+ }
83
+
84
+ function process (key) {
85
+ var value = node[key]
86
+
87
+ if (!value) return
88
+ if (isFunction(value)) return
89
+
90
+ if (isString(value)) {
91
+ node[key] = value = objectizeString(value)
92
+ }
93
+
94
+ if (isObject(value)) {
95
+ if (!value._before && !value._after) {
96
+ objectize(value, node)
97
+ return
98
+ }
99
+
100
+ value._before = value._before || resolve('_before')
101
+ value._after = value._after || resolve('_after')
102
+ return
103
+ }
104
+
105
+ throw new Error('nodes need to be either {String}, {Object} or {Function}.' + value + ' is neither.')
106
+ }
107
+
108
+ if (node._default) process('_default')
109
+
110
+ Object.keys(node)
111
+ .filter(function (key) {
112
+ return isNonCircular(key) &&
113
+ owns(node, key) &&
114
+ key !== '_before' &&
115
+ key !== '_after' &&
116
+ key !== '_default'
117
+ })
118
+ .forEach(process)
119
+ }
120
+
121
+ function functionize (node) {
122
+ Object.keys(node)
123
+ .filter(function (key) {
124
+ return isNonCircular(key) && owns(node, key)
125
+ })
126
+ .forEach(function (key) {
127
+ var value = node[key]
128
+
129
+ if (isFunction(value)) return
130
+
131
+ if (isObject(value)) {
132
+ if (!value._before && !value._after) {
133
+ functionize(value)
134
+ return
135
+ }
136
+
137
+ var before = value._before || ''
138
+ var after = value._after || ''
139
+ node[key] = surroundWith(before, after)
140
+ }
141
+ })
142
+ }
143
+
144
+ function normalize (root) {
145
+ if (!isObject(root)) {
146
+ throw new TypeError('redeyed config must be an object')
147
+ }
148
+ var normalized = cloneConfig(root, [])
149
+ objectize(normalized)
150
+ functionize(normalized)
151
+ return normalized
152
+ }
153
+
154
+ function mergeOptions (custom, required) {
155
+ var options = {}
156
+ if (custom && isObject(custom)) {
157
+ Object.keys(custom).forEach(function (key) {
158
+ Object.defineProperty(options, key, {
159
+ configurable: true,
160
+ enumerable: true,
161
+ value: custom[key],
162
+ writable: true
163
+ })
164
+ })
165
+ }
166
+ Object.keys(required).forEach(function (key) {
167
+ options[key] = required[key]
168
+ })
169
+ return options
170
+ }
171
+
172
+ function addParserToken (token, tokens, comments) {
173
+ if (token.type === 'LineComment') {
174
+ token.type = 'Line'
175
+ comments.push(token)
176
+ } else if (token.type === 'BlockComment') {
177
+ token.type = 'Block'
178
+ comments.push(token)
179
+ } else if (token.type === 'Line' || token.type === 'Block') {
180
+ comments.push(token)
181
+ } else {
182
+ if (token.type === 'Identifier' && token.value === 'static') token.type = 'Keyword'
183
+ tokens.push(token)
184
+ }
185
+ }
186
+
187
+ function tokenize (parser, code, parserOptions) {
188
+ var tokens = []
189
+ var comments = []
190
+ var delegated = false
191
+ var options = mergeOptions(parserOptions, {
192
+ range: true,
193
+ loc: true,
194
+ comment: true
195
+ })
196
+ var result = parser.tokenize(code, options, function (token) {
197
+ delegated = true
198
+ addParserToken(token, tokens, comments)
199
+ })
200
+
201
+ if (!delegated) {
202
+ var returnedTokens = Array.isArray(result) ? result : result && result.tokens
203
+ var returnedComments = !Array.isArray(result) && result && result.comments
204
+ if (Array.isArray(returnedTokens)) {
205
+ returnedTokens.forEach(function (token) {
206
+ addParserToken(token, tokens, comments)
207
+ })
208
+ }
209
+ if (Array.isArray(returnedComments)) {
210
+ returnedComments.forEach(function (comment) {
211
+ addParserToken(comment, tokens, comments)
212
+ })
213
+ }
214
+ }
215
+
216
+ return { tokens: tokens, comments: comments }
217
+ }
218
+
219
+ function mergeTokensAndComments (tokens, comments) {
220
+ var all = Object.create(null)
221
+
222
+ function addToAllByRangeStart (token) {
223
+ all[String(token.range[0])] = token
224
+ }
225
+
226
+ tokens.forEach(addToAllByRangeStart)
227
+ comments.forEach(addToAllByRangeStart)
228
+
229
+ return Object.keys(all)
230
+ .sort(function (a, b) { return Number(a) - Number(b) })
231
+ .map(function (key) { return all[key] })
232
+ }
233
+
234
+ function maskHashbang (code) {
235
+ if (code[0] !== '#' || code[1] !== '!') {
236
+ return { code: code, hashbang: '' }
237
+ }
238
+
239
+ var newline = code.indexOf('\n')
240
+ var end = newline === -1 ? code.length : newline + 1
241
+ var hashbang = code.slice(0, end)
242
+ var replacement = newline === -1
243
+ ? ' '.repeat(end)
244
+ : ' '.repeat(end - 1) + '\n'
245
+
246
+ return {
247
+ code: replacement + code.slice(end),
248
+ hashbang: hashbang
249
+ }
250
+ }
251
+
252
+ function redeyed (code, config, opts) {
253
+ opts = opts || {}
254
+ var parser = opts.parser || esprima
255
+ var jsx = !!opts.jsx
256
+ var buildAst = jsx || !!opts.buildAst
257
+ var masked = maskHashbang(code)
258
+ var hashbang = masked.hashbang
259
+ var ast
260
+ var tokens
261
+ var comments
262
+ var lastSplitEnd = 0
263
+ var splits = []
264
+ var transformedCode
265
+ var all
266
+ var info
267
+
268
+ code = masked.code
269
+
270
+ if (buildAst) {
271
+ var parseOptions = mergeOptions(opts.parserOptions, {
272
+ tokens: true,
273
+ comment: true,
274
+ range: true,
275
+ loc: true,
276
+ tolerant: true,
277
+ jsx: true
278
+ })
279
+ ast = parser.parse(code, parseOptions)
280
+ tokens = ast.tokens || []
281
+ comments = ast.comments || []
282
+ } else {
283
+ var tokenized = tokenize(parser, code, opts.parserOptions)
284
+ tokens = tokenized.tokens
285
+ comments = tokenized.comments
286
+ }
287
+ config = normalize(config)
288
+
289
+ function tokenIndex (tokenList, token, start) {
290
+ var current
291
+ var rangeStart = token.range[0]
292
+
293
+ for (current = start; current < tokenList.length; current++) {
294
+ if (tokenList[current].range[0] === rangeStart) return current
295
+ }
296
+
297
+ throw new Error('Token %s not found at or after index: %d', token, start)
298
+ }
299
+
300
+ function process (surround, start, end, currentInfo) {
301
+ var result
302
+ var currentIndex
303
+ var nextIndex
304
+ var skip = 0
305
+ var splitEnd
306
+
307
+ result = surround(code.slice(start, end), currentInfo)
308
+ if (isObject(result)) {
309
+ splits.push(result.replacement)
310
+
311
+ currentIndex = currentInfo.tokenIndex
312
+ nextIndex = tokenIndex(currentInfo.tokens, result.skipPastToken, currentIndex)
313
+ skip = nextIndex - currentIndex
314
+ splitEnd = skip > 0 ? tokens[nextIndex - 1].range[1] : end
315
+ } else {
316
+ splits.push(result)
317
+ splitEnd = end
318
+ }
319
+
320
+ return { skip: skip, splitEnd: splitEnd }
321
+ }
322
+
323
+ function addSplit (start, end, surround, currentInfo) {
324
+ var result
325
+ var skip = 0
326
+
327
+ if (start >= end) return
328
+ if (surround) {
329
+ result = process(surround, start, end, currentInfo)
330
+ skip = result.skip
331
+ lastSplitEnd = result.splitEnd
332
+ } else {
333
+ splits.push(code.slice(start, end))
334
+ lastSplitEnd = end
335
+ }
336
+
337
+ return skip
338
+ }
339
+
340
+ all = mergeTokensAndComments(tokens, comments)
341
+ for (var tokenIdx = 0; tokenIdx < all.length; tokenIdx++) {
342
+ var token = all[tokenIdx]
343
+ var surroundForType = config[token.type]
344
+ var surround
345
+ var start
346
+ var end
347
+
348
+ if (surroundForType) {
349
+ surround = owns(surroundForType, token.value) &&
350
+ surroundForType[token.value] &&
351
+ isFunction(surroundForType[token.value])
352
+ ? surroundForType[token.value]
353
+ : surroundForType._default
354
+
355
+ start = token.range[0]
356
+ end = token.range[1]
357
+
358
+ addSplit(lastSplitEnd, start)
359
+ info = { tokenIndex: tokenIdx, tokens: all, ast: ast, code: code }
360
+ tokenIdx += addSplit(start, end, surround, info)
361
+ }
362
+ }
363
+
364
+ if (lastSplitEnd < code.length) {
365
+ addSplit(lastSplitEnd, code.length)
366
+ }
367
+
368
+ if (!opts.nojoin) {
369
+ transformedCode = splits.join('')
370
+ if (hashbang.length > 0) {
371
+ transformedCode = hashbang + transformedCode.substr(hashbang.length)
372
+ }
373
+ }
374
+
375
+ return {
376
+ ast: ast,
377
+ tokens: tokens,
378
+ comments: comments,
379
+ splits: splits,
380
+ code: transformedCode
381
+ }
382
+ }
383
+
384
+ return exportFn ? exportFn(redeyed) : redeyed
385
+ }
386
+ })()